
В предыдущих шести сессиях вы создали систему блогов с нуля. Все работает, и это здорово! Тем не менее, сам код довольно грязный — мы вместе занимались начальной загрузкой и оставили много повторяющегося кода и временных решений. Эта сессия будет посвящена тому, как вы можете очистить и исправить некоторые проблемы, которые у нас были.
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 и можете двигаться вперед гораздо быстрее. Я бы рекомендовал подумать о том, как написать эти функции заранее, чтобы вы могли немного проверить свои знания. Кроме этого, следите за обновлениями!