Краткое введение в магистраль

  1. Кто использует позвоночник? airbnb, newsblur, disqus, hulu, basecamp, полоса, irccloud, trello,… Зачем?
  2. Это не рамки
  3. зависимости
  4. Backbone.Events
  5. Backbone.View
  6. Backbone.Model и Backbone.Collection
  7. Магистраль.Рутер и Магистраль.История
  8. Заключение

Кто использует позвоночник?

Кто использует позвоночник

airbnb, newsblur, disqus, hulu, basecamp, полоса, irccloud, trello,…

Зачем?

http://backbonejs.org/#FAQ-why-backbone

Это не рамки

Backbone - это библиотека JavaScript MVP (Model View Presenter), которая, в отличие от Django, чрезвычайно легка в использовании соглашений. Фреймворки обычно рассматриваются как полностью работающие приложения, которые запускают ваш код, в отличие от библиотек, где вы импортируете их код и запускаете его самостоятельно. Backbone полностью попадает в последнюю категорию, и только благодаря использованию класса Router он начинает возвращать некоторый контроль. Также включены View, Model и Collection (of Models) и Events, которые могут использоваться как полностью автономные компоненты и часто используются таким образом наряду с другими фреймворками. Это означает, что если вы используете магистраль, у вас будет гораздо больше гибкости для создания чего-то необычного и владения судьбой вашего проекта, но с другой стороны вы столкнетесь с необходимостью написания большого количества связующего кода самостоятельно, а также формирования многие из конвенций.

зависимости

Магистраль построена на jQuery и подчеркивании. Хотя эти две библиотеки имеют некоторое перекрытие, они в основном выполняют отдельные функции; jQuery - это инструмент манипулирования DOM, который обрабатывает абстракции различных несовместимостей браузера (и даже в вечнозеленый браузер возраст предлагает много преимуществ там), и нижнее подчеркивание это в первую очередь функциональный инструмент программирования, предлагающий кросс-браузерную поддержку карт, уменьшение, и тому подобное , Большинство манипуляций с данными, которые вы делаете, могут быть значительно упрощены с помощью подчеркивания, и в процессе вы, вероятно, получите более читаемый код. Если вы работаете над проектом, который не переносится из ES6 со многими встроенными функциональными инструментами, я с энтузиазмом рекомендую использовать подчеркивание.

У подчеркивания есть еще одна превосходная особенность: шаблоны ,

// Использование необработанного текста var titleTemplate = _.template ('<h1> Welcome, <% - fullName%> </ h1>'); // или если у вас есть <script type = "text / template"> var titleTemplate = _.template ($ ('# titleTemplate')); // или если вы используете requirejs var titleTemplate = require ('tpl! templates / title'); var renderedHtml = titleTemplate ({title: 'Martin Sheen'}); $ ( '# Главный') HTML (renderedHtml).

Независимо от того, как вы относитесь к синтаксису (который можно изменить в стиле усов), наличие легких шаблонов, которые поддерживают экранирование, является огромным выигрышем и, по сути, достаточным основанием для использования подчеркивания.

Backbone.Events

Вероятно, самый повторно используемый класс в наборе инструментов Backbone События , Это можно смешать с любым существующим классом следующим образом:

// Определяем конструктор var MyClass = function () {}; // Добавляем некоторые функциональные возможности в прототип конструктора _.extend (MyClass.prototype, {someMethod: function () {var somethingUseful = doSomeThing (); // запускаем событие с именем 'someEventName' this.trigger ('someEventName', SomeUseful) ;}}); // Добавляем функциональность событий _.extend (MyClass.prototype, Backbone.Events);

И вдруг в вашем классе вырос автобус для мероприятий.

var thing = new MyClass (); thing.on ('someEventName', function (SomeUseful) {alert ('ЭТО СДЕЛАНО' + somethingUseful);}); thing.someMethod ();

Вещи, о которых мы пока не знаем, теперь могут прослушивать этот класс для событий и запускать обратные вызовы, где это необходимо.

По умолчанию классы Model, Collection, Router и View имеют смешанную функциональность Events. Это означает, что в представлении (при инициализации или визуализации) вы можете сделать:

this.listenTo (this.model, 'change', this.render);

Там в список всех событий вызвано этими компонентами в документах. Когда у слушателя также есть смешанные события, он может использовать .listenTo, который, в отличие от .on, устанавливает значение this в обратном вызове для объекта, который слушает, а не для объекта, который вызвал событие.

Backbone.View

Backbone.View вероятно, самый полезный, многократно используемый класс в наборе инструментов Backbone. Это почти все условности, и они не делают ничего, кроме того, что придумывает большинство людей, собрав что-то свое.

По сути, каждое представление связывается с элементом DOM и прослушивает события из этого элемента DOM и любого из его потомков. Это означает, что функциональность, относящаяся к пользовательскому интерфейсу вашего приложения, может быть связана с определенной частью DOM.

Представления имеют хороший декларативный формат, как показано ниже (расширение - это короткая, необязательная прокладка для упрощения наследования):

var ProfileView = Backbone.View.extend ({// Первый элемент, соответствующий селектору, становится view.el // view. $ el - сокращение для $ (view.el) // view. $ ('. selector') является сокращением для $ (view.el) .find ('. selector'); el: '.profile', // Чистое соглашение, не требуется template: profileTemplate, // Когда происходят события слева, методы справа называются событиями : {'click .edit': 'editSection', 'click .profile': 'zoomProfile'}, // Пользовательская инициализация, не нужно вызывать super initialize: function (options) {this.user = options.user; }, // Ваши пользовательские методы showInputForSection: function (section) {...}, editSection: function (ev) {// потому что это связано с представлением, это jQuery сделано // доступным как 'currentTarget' var section = $ (ev.currentTarget) .attr ('data-section'); this.showInputForSection (section);}, zoomProfile: function () {$ (ev.currentTarget) .toggleClass ('zoomed');}, // Every представление имеет метод render, который должен возвращать представление render: function () {var rendered = this.templat e ({user: this.user}); . Это $ el.html (оказываемых); верни это; }});

Наконец, чтобы использовать это представление:

// Вы также можете передать модель, коллекцию, el, id, className, tagName, атрибуты и события, чтобы переопределить декларативные значения по умолчанию var view = new ProfileView ({user: someUserObject}); view.render (); // Материал появляется в .profile! // Как только вы закончили с представлением view.undelegateEvents (); view.remove (); // NB. Почему не удалить вызов undelegateEvents? NFI m8. Ненавижу, что это не так.

Следующим шагом является вложение просмотров. Вы можете иметь представление, которое отображает список, но для каждого из элементов списка оно создает новое представление для отображения элемента списка и прослушивания событий для этого элемента.

render: {// Создание базового шаблона "<ul> </ ul>" this. $ el.html (this.template ()); _.each (this.collection.models, function (model) {// Создание нового элемента "li" в качестве представления для каждой модели var itemView = new ModelView ({tagName: 'li'}); // Визуализация представления itemView.render (); // Элемент li в jquery теперь доступен в itemView. $ el this. $ ('ul') // найти тег ul в родительском представлении .append (itemView. $ el); / / добавить к нему этот тег li}); }

Как вы решите разбить свою страницу, полностью зависит от вас и вашего приложения.

Backbone.Model и Backbone.Collection

Магистраль-х модель а также Коллекция классы предназначены для очень стандартных конечных точек REST. Может быть больно заставлять их поддерживать что-то еще, хотя это достижимо.

Предполагая, что у вас есть конечная точка / элементы HTTP, которые могут:

  • есть список предметов, полученных из него
  • иметь один элемент GET'd из / items / ID

И если вы собираетесь сохранить любые изменения обратно в базу данных:

  • есть новые предметы, размещенные на нем
  • есть существующие элементы, в / items / ID PUT, PATCHed и DELETEd

Тогда все готово для использования всех функций в Backbone.Model и Backbone.Collection.

var Item = Backbone.Model.extend ({someMethod: function () {// выполнить некоторые вычисления для данных}}); var Items = Backbone.Collection.extend ({model: Item,});

Для определения подкласса Model ничего не требуется, хотя вы можете указать имя атрибута id и различные другие настраиваемые параметры, а также настроить предварительную обработку данных при их получении. Подклассы коллекции должны иметь атрибут модели, указывающий, какой класс Model используется для создания новых моделей из извлеченных данных.

Огромным преимуществом Model and Collection является их общая функциональность синхронизации - сохранение их состояния на сервере и информирование о том, что изменилось. Также приятно иметь возможность прикреплять методы к модели / коллекции для выполнения расчетов с данными.

Давайте создадим коллекцию и получим ее.

var items = new Items (); // Fetch возвращает jQuery обещание items.fetch (). done (function () {items.models // список объектов Item items.get (4) // получить объект Item по его идентификатору});

Легко. Теперь давайте создадим новый экземпляр модели и сохраним его в базе данных:

var newItem = new Item ({some: 'data'}); items.Add (newItem); newItem .save () .done (function () {messages.success ('Элемент сохранен');}) .fail (function () {messages.danger ('Элемент не может быть сохранен lol');});

Или выбрать модели самостоятельно:

var item = new Item ({id: 5}); item .fetch () .done (function () {someView.render ();}); // или использовать События! this.listenTo (item, 'change', this.render); item.fetch ();

И чтобы получить / установить атрибуты на модели:

var attr = item.get ('attributeName'); item.set ('attributeName', newValue); // запускает события 'change' и 'change: attributeName'

Магистраль.Рутер и Магистраль.История

Вы уже поняли, что все вышеперечисленное прекрасно работает в типичном, дружественном к SEO, не требующем узла, просмотре ftw многостраничного приложения постбэк. Но как насчет того, когда вы хотите одностраничное приложение? Для этого магистраль предлагает Маршрутизатор и Историю.

Классы маршрутизации сопоставляют URL-адреса с обратными вызовами, которые обычно создают экземпляры классов View и / или Model.

History делает немного больше, чем просто обнаруживает изменения в URL страницы (будь то изменение #! Page / фрагмента / или с помощью pushState в HTML 5) и, после получения этого события, координирует классы маршрутизатора вашего приложения соответственно на основании URL-адресов, которые он обнаруживает. Именно Backbone.History переносит магистраль из категории библиотеки в категорию фреймворка.

History и Router обычно используются вместе, так что вот несколько примеров использования:

var ApplicationRouter = Router.extend ({router: {'profile': 'profile', 'items': 'items', 'item /: id': 'item',}, profile: function () {var profile = new ProfileView (); profile.render ();}, items: function () {var items = new Items (); var view = new ItemsView ({items: items}); items.fetch (). Done (function () {items.render ();});}, item: function (id) {var item = new Item ({id: id}) var view = new ItemView ({item: item}); item.fetch (). done (function () {view.render ();});}});

Обратите внимание, что выше, я запускаю выборку с маршрутизатора. Вместо этого вы можете сделать так, чтобы ваш вид отображал загрузочный экран и извлекал коллекцию / модель изнутри. Или, при инициализации представления, он может выполнить this.listenTo (item, 'sync', this.render), и в этом случае вашим маршрутизаторам нужно только создать экземпляр модели, создать экземпляр представления и передать модель, а затем извлечь модель , Хребет оставляет все это вам!

Наконец, давайте использовать Backbone.History воплотить все это в жизнь:

$ (function () {// Маршрутизаторы регистрируют себя new ApplicationRouter (); if (someCustomSwitch) {new CustomSiteRouter ();} // История уже создана в Backbone.history Backbone.history.start ({pushState: true}); });

Теперь наиболее распространенный способ использования маршрутизатора - прослушивать событие щелчка по ссылке, перехватывать событие и вместо того, чтобы позволить браузеру загрузить новую страницу, предотвращать дефолт и вместо этого запускать Backbone.history.navigate ('/ url / from / link ', {trigger: true}); Это запустит метод, связанный с пройденным маршрутом, а затем обновит URL с помощью pushState. Это ключ: каждый метод маршрутизатора должен быть идемпотентным, создавая столько страниц, сколько требуется из ничего. Иногда этот метод вызывается на другой странице, иногда нет. Вызов history.navigate также создаст новую запись истории в истории браузера (хотя этого можно избежать, передав {trigger: true, replace: true}.

Если пользователь нажимает назад / вперед в браузере, URL-адрес изменится, и Backbone.history снова найдет новый URL-адрес и выполнит метод, связанный с этим URL-адресом. Если ничего не найдено, событие передается в браузер, и браузер выполняет обычное изменение страницы. В этом случае вы должны быть уверены, что в вашем методе маршрутизатора вызовите .remove и .undelegateEvents для любых созданных экземпляров представлений, которые вам больше не нужны, иначе обратные вызовы для них могут все еще срабатывать. Да, это невероятно сложно.

Наконец, вы иногда окажетесь в положении, когда вы обновили одну небольшую часть страницы, возможно, какой-то вложенный вид, но вы хотите, чтобы это изменение было отражено в URL. Вы не обязательно хотите запускать метод маршрутизатора, потому что вся работа была выполнена, но у вас есть метод маршрутизатора, который может восстановить новое состояние страницы, если пользователь загружал эту страницу из полного обновления. В этом случае вы можете вызвать Backbone.history.navigate ('/ new / path'); и он добавит новую запись в историю, не вызывая связанный метод.

Заключение

Магистраль не состоялась. Он предоставляет огромное количество связующего кода, что очень полезно и сразу ставит вас в гораздо лучшее положение, чем если бы вы просто использовали jquery. Тем не менее, для каждого приложения должно быть написано больше связующего кода, чтобы он мог сделать намного больше. С одной стороны, это означает, что вы получаете огромную гибкость, что чрезвычайно полезно, учитывая эзотерическую природу приложений, которые мы создаем, а также дает вам возможность сделать ваши приложения невероятно быстрыми, так как вы не выполняете много общего -целевой клейкий код из гораздо более сложных фреймворков. Это также дает вам возможность непреднамеренно повеситься.

Если вы ищете что-то простое и значительно более мощное, чем jQuery, но менее болезненный риск, чем ужасный грязный мир правильных структур JavaScript (см. Также: сотни «сожалеющих» постов в блоге), Backbone - это отличное место для начала.

О нас : Isotoma является компанией по разработке программного обеспечения на заказ, базирующейся в Йорке и Лондоне, специализирующейся на веб-приложениях, мобильных приложениях и дизайне продуктов. Если вы хотите узнать больше, вы можете обзор нашей работы или же связаться ,

Кто использует позвоночник?
Airbnb, newsblur, disqus, hulu, basecamp, полоса, irccloud, trello,… Зачем?
Airbnb, newsblur, disqus, hulu, basecamp, полоса, irccloud, trello,… Зачем?
Почему не удалить вызов undelegateEvents?
Но как насчет того, когда вы хотите одностраничное приложение?