В предыдущих шести сессиях вы создали систему блогов с нуля. Все работает, и это здорово! Тем не менее, сам код довольно грязный — мы вместе занимались начальной загрузкой и оставили много повторяющегося кода и временных решений. Эта сессия будет посвящена тому, как вы можете очистить и исправить некоторые проблемы, которые у нас были.
1. Объедините index.html и admin.html
Прежде всего, поскольку у нас теперь есть маршрутизатор (если вы пропустили этот сеанс, ознакомьтесь с частью 5: Маршрутизатор ), нам больше не нужны два отдельных файла .html
и .js
. Давайте объединим их вместе.
Шаг 1: Слияние файлов
На этом этапе я бы предложил объединить admin.html
и admin.js
и переименовать их в index.html
и blog.js
потому что они содержат больше логики и кода, но вы можете сделать это любым способом. Это должно быть довольно просто.
Если вы переименовываете файлы, просто убедитесь, что вы blog.js
на blog.js
в новом index.html
(ранее admin.html
). Кроме того, не забудьте скопировать более #blogs-tpl
из старого файла index.html
в новый и скопировать BlogsView
из старого файла blog.js
в новый.
Теперь посетите http: // localhost / your-directory /, и вы должны увидеть экран входа по умолчанию (или экран администратора, если вы уже вошли в систему).
Шаг 2: Обновите Маршрутизатор
Затем мы можем добавить новый шаблон URL в маршрутизаторе, чтобы сопоставить корневой URL с новой функцией; мы можем назвать это index()
:
1
2
3
4
|
routes: {
»: ‘index’,
…
},
|
Эта функция index()
должна отображать то, что было ранее на главной странице.
01
02
03
04
05
06
07
08
09
10
11
12
|
index: function() {
this.blogs.fetch({
success: function(blogs) {
var blogsView = new BlogsView({ collection: blogs });
blogsView.render();
$(‘.main-container’).html(blogsView.el);
},
error: function(blogs, error) {
console.log(error);
}
});
}
|
И чтобы увидеть, как это работает, давайте по умолчанию перенаправим на этот URL при запуске маршрутизатора:
1
2
3
4
|
start: function(){
Parse.history.start({pushState: true});
this.navigate(», { trigger: true });
}
|
Шаг 3: Обновить Nav
Следующее, что нужно обновить панель навигации вверху. Давайте изменим эти HTML-файлы на URL-адреса здесь:
1
2
3
4
|
<nav class=»blog-nav»>
<a class=»blog-nav-item active» href=»»>Home</a>
<a class=»blog-nav-item» href=»admin»>Admin</a>
</nav>
|
И чтобы они работали, нам нужно добавить событие в .blog-nav-item
чтобы использовать blogRouter.navigate()
а не событие ссылки по умолчанию:
1
2
3
4
5
|
$(document).on(‘click’, ‘.blog-nav-item’, function(e) {
e.preventDefault();
var href = $(e.target).attr(‘href’);
blogRouter.navigate(href, { trigger: true });
});
|
И давайте добавим логику для переключения класса .active
:
1
2
3
4
5
6
|
$(document).on(‘click’, ‘.blog-nav-item’, function(e) {
e.preventDefault();
var href = $(e.target).attr(‘href’);
blogRouter.navigate(href, { trigger: true });
$(this).addClass(‘active’).siblings().removeClass(‘active’);
});
|
Теперь, если вы нажмете вокруг, все должно работать!
2. Слияние Добавить и изменить
Двигаясь дальше, мы видим, что AddBlogView
и EditBlogView
очень похожи. Как и функции update()
и create()
в классе Blog
. Давайте объединить их.
Шаг 1: Объединить # add-tpl и # edit-tpl
Во-первых, давайте объединим два шаблона в index.html
чтобы они были #write-tpl
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<script id=»write-tpl» type=»text/x-handlebars-template»>
<h2>{{form_title}}</h2>
<form class=»form-write» role=»form»>
<div class=»form-group»>
<label for=»title»>Title</label>
<input name=»title» type=»text» class=»form-control» id=»title» value=»{{title}}»></input>
</div>
<div class=»form-group»>
<label for=»content»>Content</label>
<textarea name=»content» class=»form-control» rows=»20″>{{{content}}}</textarea>
</div>
<button class=»btn btn-lg btn-primary btn-block» type=»submit»>Submit</button>
</form>
</script>
|
Вы можете видеть, что это в основном #edit-tpl
с изменениями имени класса и динамическим заголовком формы. Мы просто передадим ""
в title
и content
при добавлении нового блога.
Шаг 2: Объединить функции update () и create ()
Далее, давайте объединим функции update()
и create()
в классе Blog. Мы можем this.set().save()
для update()
и create()
. Для полей, которые не должны быть затронуты функцией update()
, мы можем заполнить текущим значением:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
update: function(title, content) {
this.set({
‘title’: title,
‘content’: content,
// Set author to the existing blog author if editing, use current user if creating
// The same logic goes into the following three fields
‘author’: this.get(‘author’) ||
‘authorName’: this.get(‘authorName’) ||
‘time’: this.get(‘time’) ||
}).save(null, {
success: function(blog) {
alert(‘You updated a new blog: ‘ + blog.get(‘title’));
},
error: function(blog, error) {
console.log(blog);
console.log(error);
}
});
}
|
Шаг 3: Слияние AddBlogView и EditBlogView
Теперь пришло время объединить два представления:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
WriteBlogView = Parse.View.extend({
template: Handlebars.compile($(‘#write-tpl’).html()),
events: {
‘submit .form-write’: ‘submit’
},
submit: function(e) {
e.preventDefault();
var data = $(e.target).serializeArray();
// If there’s no blog data, then create a new blog
this.model = this.model ||
this.model.update(data[0].value, data[1].value);
},
render: function(){
var attributes;
// If the user is editing a blog, that means there will be a blog set as this.model
// therefore, we use this logic to render different titles and pass in empty strings
if (this.model) {
attributes = this.model.toJSON();
attributes.form_title = ‘Edit Blog’;
} else {
attributes = {
form_title: ‘Add a Blog’,
title: »,
content: »
}
}
this.$el.html(this.template(attributes)).find(‘textarea’).wysihtml5();
}
})
|
Обратите внимание, как вы можете использовать if(this.model)
для if(this.model)
между функциями добавления и редактирования.
Шаг 4: Обновите Маршрутизатор
Наконец, давайте WriteBlogView
с этим новым WriteBlogView
в маршрутизаторе. Просто измените оба представления на WriteBlogView
и он все равно должен работать как обычно.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
add: function() {
// Check login
if (!Parse.User.current()) {
this.navigate(‘login’, { trigger: true });
} else {
var writeBlogView = new WriteBlogView();
writeBlogView.render();
$container.html(writeBlogView.el);
}
},
edit: function(id) {
// Check login
if (!Parse.User.current()) {
this.navigate(‘login’, { trigger: true });
} else {
var query = new Parse.Query(Blog);
query.get(id, {
success: function(blog) {
var writeBlogView = new WriteBlogView({ model: blog });
writeBlogView.render();
$container.html(writeBlogView.el);
},
error: function(blog, error) {
console.log(error);
}
});
}
}
|
Обратите внимание, что вы также должны отправлять посетителей обратно на страницу входа, если они не вошли в систему.
3. Добавить список контроля доступа в блоги
Теперь, когда мы удалили весь повторяющийся код, теперь мы можем перейти к некоторым функциям, которые можно улучшить.
Многие из вас спрашивали, как мы можем обеспечить безопасность данных, если API находится в коде. Parse.js предоставляет списки контроля доступа (ACL) как на уровне классов, так и на уровне элементов, которые помогают управлять доступом пользователей. Мы говорили о ACL на уровне класса в Части 3: Вход пользователя . Сегодня я покажу вам, как добавить ACL уровня элемента.
В качестве примера, давайте предположим, что мы хотим, чтобы каждый блог мог редактироваться только его первоначальным автором.
Чтобы это произошло, нам нужно установить поле ACL
в функции update()
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
update: function(title, content) {
// Only set ACL if the blog doesn’t have it
if ( !this.get(‘ACL’) ) {
// Create an ACL object to grant access to the current user
// (also the author of the newly created blog)
var blogACL = new Parse.ACL(Parse.User.current());
// Grant read-read only access to the public so everyone can see it
blogACL.setPublicReadAccess(true);
// Set this ACL object to the ACL field
this.setACL(blogACL);
}
this.set({
…
});
}
|
4. Корневой и статический URL
Еще одна проблема, которая может возникнуть у многих из вас, заключается в том, что довольно сложно протестировать созданную вами систему блогов. Каждый раз, когда вы тестируете, вы должны возвращаться к http: // localhost / your-directory / для запуска маршрутизатора.
Давайте сначала решим эту проблему.
Шаг 1: добавление рута в BlogRouter.start ()
Parse.js делает это довольно легко, поэтому давайте просто изменим BlogRouter.start()
чтобы установить корень файла.
1
2
3
4
5
6
|
start: function(){
Parse.history.start({
// put in your directory below
root: ‘/tutorial_blog/’
});
}
|
Обратите внимание, что теперь мы можем this.navigate()
функцию this.navigate()
.
Шаг 2: Статический URL
Еще одна проблема с URL-адресами, которые у нас есть сейчас, заключается в том, что их нельзя добавить в закладки или пересмотреть. Все, что вы хотите сделать, нужно начинать с основного URL. Например, если вы посещаете http: // localhost / blog / admin , маршрутизатор настроен на прием этого шаблона URL, но сервер по-прежнему возвращает 404. Это потому, что когда вы посещаете /admin
, ваш сервер не знает, что он должен идти в index.html
чтобы запустить маршрутизатор в первую очередь.
Одним из способов решения этой проблемы является настройка вашего сервера таким образом, чтобы он перенаправлял все URL-адреса в index.html
. Но это не совсем в рамках этого класса. Мы собираемся попробовать другой метод: добавить #/
перед всеми нашими URL.
URL-адрес панели администратора будет выглядеть следующим образом: http: // localhost / blog / # / admin . Это не совсем идеально, но это легкий путь. Когда браузер встречает /#
, он не будет обрабатывать оставшуюся часть URL как путь к файлу; вместо этого он направит пользователя на index.html, чтобы наш маршрутизатор мог подобрать остальное.
Теперь давайте продолжим и изменим атрибут href
всех тегов <a>
в index.html
примерно так:
1
|
<a class=»app-link» href=»edit/{{url}}»>Edit</a>
|
что-то вроде этого:
1
|
<a class=»app-link» href=»#/edit/{{url}}»>Edit</a>
|
Точно так же давайте изменим все BlogApp.navigate()
в blog.js
примерно так:
1
|
BlogApp.navigate(‘admin’, { trigger: true });
|
что-то вроде этого:
1
|
BlogApp.navigate(‘#/admin’, { trigger: true });
|
Вы также можете удалить некоторые из событий, чтобы использовать тег <a>
.
Например, кнопка « Добавить новый блог » используется для использования события:
1
2
3
4
5
6
|
events: {
‘click .add-blog’: ‘add’
},
add: function(){
blogRouter.navigate(‘#/add’, { trigger: true });
}
|
Мы можем вынуть их и заменить на ссылку в index.html
:
1
|
<a href=»#/add» class=»add-blog btn btn-lg btn-primary»>Add a New Blog</a>
|
Вы также можете отключить эту функцию, так как URL будут работать сами по себе:
1
2
3
4
5
6
|
$(document).on(‘click’, ‘.blog-nav-item’, function(e) {
e.preventDefault();
var href = $(e.target).attr(‘href’);
blogRouter.navigate(href, { trigger: true });
$(this).addClass(‘active’).siblings().removeClass(‘active’);
});
|
Давайте также пока удалим active
класс, но мы добавим его обратно и сделаем так, чтобы он работал в последующих сеансах другим способом.
1
2
3
4
|
<nav class=»blog-nav»>
<a class=»blog-nav-item» href=»»>Home</a>
<a class=»blog-nav-item» href=»#/admin»>Admin</a>
</nav>
|
Хорошо, зайдите в свой блог, протестируйте и убедитесь, что все ссылки теперь на http: // localhost / # / …, кроме домашней страницы.
Теперь у вас есть URL, которые вы можете обновить и просмотреть. Надеюсь, это сделает вашу жизнь намного проще!
Бонус: другие исправления и улучшения
Если вы не возражаете против сверхдлинного учебника и хотели бы внести еще несколько улучшений, вот несколько других исправлений и улучшений, которые вы можете сделать.
Шаг 1: сортировка
Вы также можете заметить, что блоги сортируются от самых ранних до самых последних. Обычно мы ожидаем увидеть последние блоги в первую очередь. Итак, давайте изменим коллекцию Blogs
чтобы отсортировать их в следующем порядке:
1
2
3
4
|
Blogs = Parse.Collection.extend({
model: Blog,
query: (new Parse.Query(Blog)).descending(‘createdAt’)
})
|
Шаг 2: Перенаправить на WelcomeView после обновления ()
Вот еще одна вещь, которую мы можем улучшить. Вместо появления окна с предупреждением после обновления блога, давайте просто перенаправим на страницу /admin
:
01
02
03
04
05
06
07
08
09
10
|
this.set({
…
}).save(null, {
success: function(blog) {
blogRouter.navigate(‘#/admin’, { trigger: true });
},
error: function(blog, error) {
…
}
});
|
Шаг 3: объединить AdminView в WelcomeView
Если вы приступите к очистке, вы также можете объединить AdminView и WelcomeView в одно — нет необходимости иметь два отдельных представления.
Опять же, сначала HTML-шаблон:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<script id=»admin-tpl» type=»text/x-handlebars-template»>
<h2>Welcome, {{username}}!</h2>
<a href=»#/add» class=»add-blog btn btn-lg btn-primary»>Add a New Blog</a>
<table>
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Time</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{{#each blog}}
<tr>
<td><a class=»app-link» href=»#/edit/{{objectId}}»>{{title}}</a></td>
<td>{{authorName}}</td>
<td>{{time}}</td>
<td>
<a class=»app-link app-edit» href=»#/edit/{{objectId}}»>Edit</a> |
<a class=»app-link» href=»#»>Delete</a>
</td>
</tr>
{{/each}}
</tbody>
</table>
</script>
|
Затем давайте изменим BlogRouter.admin()
для передачи username
в AdminView
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
admin: function() {
var currentUser = Parse.User.current();
// Check login
if (!currentUser) BlogApp.navigate(‘#/login’, { trigger: true });
this.blogs.fetch({
success: function(blogs) {
var blogsAdminView = new BlogsAdminView({
// Pass in current username to be rendered in #admin-tpl
username: currentUser.get(‘username’),
collection: blogs
});
blogsAdminView.render();
$(‘.main-container’).html(blogsAdminView.el);
},
error: function(blogs, error) {
console.log(error);
}
});
}
|
А затем передайте username
которое будет отображено в #admin-tpl
:
01
02
03
04
05
06
07
08
09
10
11
|
BlogsAdminView = Parse.View.extend({
template: Handlebars.compile($(‘#admin-tpl’).html()),
render: function() {
var collection = {
// Pass in username as variable to be used in the template
username: this.options.username,
blog: this.collection.toJSON()
};
this.$el.html(this.template(collection));
}
})
|
Шаг 4: $ контейнер
Наконец, мы можем хранить $('.main-container')
как переменную, чтобы избежать нескольких запросов.
1
|
var $container = $(‘.main-container’);
|
И просто замените все $('.main-container')
на $container
.
Вывод
Прежде всего, поздравляем с завершением! Это была длинная сессия, но вы очистили весь проект. Кроме того, вы также добавили ACL в блоги, внедрили статические URL-адреса и внесли множество других исправлений. Теперь это действительно солидный проект.
На следующем занятии мы ускорим процесс и добавим три новые функции: просмотр одного блога, удаление блога и выход из системы, потому что теперь вы хорошо разбираетесь в Parse.js и можете двигаться вперед гораздо быстрее. Я бы рекомендовал подумать о том, как написать эти функции заранее, чтобы вы могли немного проверить свои знания. Кроме этого, следите за обновлениями!