Думаю будет интересно только тем, кто только начал работать с Backbone.js. Хотя…
Для чего это нужно?
Представьте что у вас есть приложение, но котором надо организовать систему уведомлений (новое письмо, лайк, активность друга и т.д.). Отображение подобного рода уведомлений будет не везде, а в определенных участках приложения. Например:
- на главной странице нужно отображать все уведомления
- на странице твиттера нужны только уведомления которые касаются только его
- на «другой» странице нужны все уведомления кроме твиттера
Ссылки
Структура
- app
- modules
anotherOne.js
main.js
navigation.js
notification.js
twitter.js
app.js
init.js
- assets
- css
index.css
- js
- libs
backbone.js
jquery-1.7.2.js
underscore.js
index.html
Ближе к делу
Первым делом запускаем локальный HTTP-сервер:
python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
Который будет доступен по адресу http://localhost:8000
Создаем index.html, подключаем необходимые библиотеки, стиль, запускаем и смотрим в папку app.
В файле init.js создаем переменную app, которая может делегировать событиями, менять роут, получать и компилировать шаблон (с кешированием)
var app = _.extend({
templates : {},
template : function(_id, _data) {
var id = _id.slice(1);
if (!this.templates[id]) {
this.templates[id] = _.template($(_id).html());
}
return this.templates[id](_data);
}
}, Backbone.Events)
Файл app.js отвечает за инициализацию и запуск приложения. Создадим 4 роута — три обычные и один волшебный, который будет перехватывать битые роуты (или их отсутствие, например, при первой загрузке)
routes : {
'main' : 'main',
'twitter' : 'twitter',
'anotherOne' : 'anotherOne',
'*action' : 'otherRoute'
}
Если сработает этот волшебный роут пользователь будет перенаправлен на роут main.
otherRoute : function () {
this.navigate('main', {trigger:true});
}
Каждый раз, когда меняется роут мы будем тригерить событие, которое сможет слушать любой из модулей (что бы просто быть в курсе или менять какие-то параметры в соответствии с новым роутом). В данном случае это событие будет слушать только модуль navigation.
Рассмотрим структуру модуля main (twitter, anotherOne — идентичны ему).
Котроллер инициализирует и отрисовывает MainView
app.Main = function() {
var view = new this.MainView(); // инициализируем
view.render(); // отрисовываем
}
app.Main.prototype.MainView = Backbone.View.extend({
el : '#main', // id елемента-родителя
template : '#template-main', // id шаблона
initialize : function () {
_.bindAll(this);
},
render : function() {
// компилируем шаблон и заменяем им HTML родителя
this.$el.html(app.template(this.template));
}
})
Очень часто встречаю такую запись
$(this.el)
Так делать не рекомендуется. Backbone кеширует el и позволяет обратиться к нему через
this.$el
Модуль navigation
Подписываемся на обновления роута:
app.on('navigation_changed', view.changeNavigation);
В случае, если роут изменится мы попадем в функцию changeNavigation:
changeNavigation : function (location) {
$(this.$location).hide(); // прячем все страницы
$(this.$notification).hide(); // прячем все уведомления
$('#' + location).show(); // показываем текущую страницу
$(this.$button).removeClass('active'); // сбрасываем стиль кнопки-индикатора
// делаем активной нужную кнопку
$(this.$button + '[data-id="' + location + '"]').addClass('active');
// показываем уведомления, которые должны отображаться везде
$(this.$notification + '[data-include-in="*"]').show();
// показываем уведомления которые должны отображаться на текущей странице
$(this.$notification + '[data-include-in*="' + location + '"]').show();
// показываем все уведомления типа exclude
$(this.$notification + '[data-exclude-from]').show();
// и прячем те, которые не должны попасть на текущую страницу
$(this.$notification + '[data-exclude-from*="' + location + '"]').hide();
}
Модуль notification
Инициализируем NotificationView и рендерим блок с настройками.
app.Notification = function() {
var view = new this.NotificationView();
view.renderSettings();
}
Вешаем события onclick на кнопки закрытия и создания уведомления соответственно.
initialize : function () {
_.bindAll(this);
this.$el.on('click', this.$closeButton, this.closeNotificationHandler);
$(this.$settings).on('click', this.$addButton, this.addNotificationHandler)
}
После клика по кнопке закрытия ищем ближайшего родителя этой кнопки, анимируем его свертывание и удаляем из DOM.
closeNotificationHandler : function (e) {
var $notification = $(e.currentTarget).parents(this.$notification);
$notification.slideUp(100, function() {
$notification.remove();
});
}
Сюда мы попадаем после клика по кнопке "Показать уведомление".
addNotificationHandler : function () {
var $location = $(this.$locationCheckbox + ':checked'), // получаем выбранные локации
type = $(this.$typeRadio + ':checked').attr('value'), // получаем тип уведомления
index,
settings = {
location : [],
type : type,
show : false, // по умолчанию уведомление скрыто
message : null
};
// если установлен тип exclude-from и ни одна локация не выделана - можно
// просто проигнорировать это уведомление
if (!type || !$location.length && type !== 'include-in') return false;
if ($location.length) { // выбрана какая-то локация(и)
$.each($location, function(key, element) {
// наполняем массив локациями
settings.location.push(element.value);
});
// проверяем есть ли текущая локация в списке
index = settings.location.indexOf(Backbone.history.fragment);
// склеиваем все локации в строку с пробелом в роли разделителя.
settings.location = settings.location.join(' ');
// показываем уведомление если:
// 1) установлен тип include-in и мы находимся в одной из выбранных локаций.
// 2) установлен тип exclude-from и мы не находимся в одной из выбранных локаций.
settings.show = type === 'include-in' ? index !== -1 : index === -1;
}
else {
// ни одна локация не выбрана - показываем уведомление везде
settings.show = true;
settings.location = '*';
}
settings.message = type + ': ' + settings.location;
this.addNotification(settings);
}
include-in — data-аттрибут в котором хранится список роутов (через пробел, или * — для всех роутов), где должны показываться уведомление
exclude-from — data-аттрибут в котором хранится список роутов (через пробел), где не должны показываться уведомление
Автор: vermilion1