Блог начинающего фронтендера

Знакомимся с Backbone.js

Backbone.js — JavaScript-библиотека, основанная на шаблоне проектирования Model-View-Presenter, предназначена для разработки веб-приложений с поддержкой RESTful JSON интерфейса.

Установка

  • Существует жесткая зависимость от библиотеки Underscore
  • Необходимо так же устанавливать jQuery
  • Сам Backbone прописывается только после этих двух библиотек

Содержание

Backbone.js состоит из следующих классов:

  • Model (Модель)
  • Collection (Коллекция)
  • View (Представление)
  • Router (Роутер)

Модель (model)

Модель — это какая-либо сущность предметной области, будь то пользователь, книга, продукт, элемент меню. Модели в Backbone.js позволяют хранить данные приложения, имеют методы для добавления, изменения и удаления этих данных (атрибуты модели).

Пример создания модели:

var Book = Backbone.Model.extend({
  //Каждый раз при вызове экземпляра модели вызывается метод initialize()
  initialize: function() {  
    console.log('Book was initialized'); 
  },
  //Каждый экземпляр модели при создании может содержать некоторые начальные поля
  defaults: {               
    title: 'No title',    
    author: 'unknown',
    releaseDate: 2011,
    description: ''
  }
});

Создать новый экземпляр модели можно с помощью new:

// создаем экземпляр модели
var oBook = new Book({ title: 'Alice in Wonderland', author: 'Lewis Caroll' });
// считываем атрибут title
var sBookTitle = oBook.get('title'); 
// устанавливаем атрибут releaseDate
oBook.set({ releaseDate: '1865'  }); 

Изменения в примере выше сохраняются только в оперативной памяти. Если вы хотите сохранить изменения модели на сервер, используйте метод save:

oBook.save();

Установка атрибутов

Установить значения атрибутов можно как при инициализации экземпляра модели:

var testUser = new User({
  name: 'Frank'
});

так и с помощью сеттера:

var testUser = new User();
testUser.set({ name: 'Frank' });

Получение атрибутов

Внутри модели все данные хранятся в объекте attributes. Получить значение атрибута можно с помощью метода get().

var testUser = new User({ name: 'Frank' });
var name = testUser.get('name');

Получить все атрибуты модели можно с помощью метода toJSON():

var attributes = user.toJSON();

События изменения состояния модели

На событие изменения любого атрибута модели может быть навешен обработчик:

App.User = Backbone.Model.extend({
  initialize: function() {
      this.bind('change:name', function() {
          var name = this.get('name');
          alert(name);
      });
  }
var testUser = new User();

В примере выше мы повесили обработчик только на событие изменения атрибута name. Обработчик будет срабатывать при изменении любого атрибута модели:

this.bind('change', function() {}); 

Валидация модели

Backbone.js позволяет определить метод validate() у модели, чтобы проверить корректность данных.

По умолчанию, валидация происходит при вызове метода save() или когда метод set() вызван с опцией {validate: true}.

var user = new Backbone.Model({ name: 'Frank' }); //не уверен правильно ли что user а не User
User.validate = function(attributes) {
    if (!attributes.name) {
        return 'Name is required';
    }
};
User.set({ name: 'John' }); //тут тоже не понял
User.unset('name', { validate: true }); //false

Метод validate() всегда возвращает текст ошибки. Если все поля модели корректны — функция не должна ничего возвращать.

Если возвращается ошибка, то:

  • срабатывает событие invalid модели и устанавливается свойство validationError, в котором сохраняется текст ошибки;
  • метод save() не срабатывает и данные на сервере не изменяются

Представления (View)

Представления в Backbone.js выполняют две основные функции:

  • Отображение состояния приложения и данных модели пользователям;
  • Реагирование на события от элементов DOM и моделей/коллекций

Cоздадим простое представление:

var BookView = Backbone.View.extend({
    tagName: ‘div’,
    className: ‘book-item’,
    render: function() {
        this.$el.html(this.model.get(‘title’));
        return this;
    }
});

Атрибут $el ссылается на обертку, которую создает представление. В нашем примере, мы создали элемент <div> с классом book-item и поместили в него заголовок книги.

В этом примере мы не использовали возможность шаблонизации, если представление более сложное, можно использовать шаблонизатор из библиотеки Underscore.js.

Давайте изменим наш пример с использованием шаблонизатора:

var BookView = Backbone.View.extend({
    tagName: 'div',
    className: 'book-item',
    template: _.template($('#bookTemplate').html()),
  
    render: function() {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    }
});

Сам шаблон можно поместить непосредственно на HTML-странице:

<script id='bookTemplate' type='text/template'>
    <h3 class="title"><%= title %></h3>
    <div class="description">
  <p class="release-date"><%= previewText %></p>
  <p><%= previewText %></p>         
    </div>
</script>

Также представления в Backbone.js могут слушать события от элементов DOM и от моделей и коллекций.

events: {
  'click .title': 'onTitleClick'
},
'onTitleClick': function(event) {
  alert('Клик');
}

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

Представления (View) в Backbone.js отвечают за отображение данных приложения, а также могут реагировать на события, возникающие в моделях, коллекциях или события DOM-элементов.

SearchView = Backbone.View.extend({
  initialize: function() {
    alert(‘Initialized!’);
  }
});
var searchView = new SearchView();

Функция initialize() вызывается при инициализации объекта представления

Свойство el

Свойство el представления — это ссылка на DOM-элемент. Представления в Backbone.js формируют внутри el отображение данных и только потом вставляют этот элемент в DOM.

Каждое представление должно быть связано с DOM-элементом и, если свойство el явно не определено, Backbone создает новый элемент. Управлять созданием этого элемента можно с помощью трех свойств: tagName, id и className, определяющих, соответственно, тег, id и class. По умолчанию, если ни одно из этих свойств не задано — будет создан пустой элемент <div></div>.

Для вызова jQuery (или Zepto) функций представление Backbone имеет свойство $el. Свойство $el хранит закешированный объект $(view.el).

Свяжем наше представление с существующим элементом div#search_container:

SearchView = Backbone.View.extend({
  initialize: function() {
    alert('Initialized!');
  }
});
var searchView = new SearchView({ el: $('#search_container') });

Если необходимо связать существующее представление с другим DOM-элементом — можно воспользоваться методом setElement. Такое изменение требует привязки всех событий к новому элементу.

Метод setElement удаляет обработчики всех событий элемента $el, создает новую ссылку $el и снова привязывает обработчики событий.

Рендеринг представления

Для отображения представления в DOM необходимо реализовать метод render() и вызвать его при инициализации представления.

Библиотека Underscore.js, использующаяся в Backbone.js, предоставляет собственное решение для шаблонизации. Однако при желании можно использовать любой другой шаблонизатор.

SearchView = Backbone.View.extend({
  initialize: function() {
    alert('Initialized!');
  },
  render: function() {
    var template = _.template($('#search_template').html(), {});
    this.$el.html(template);
    return this;
  }
});
var searchView = new SearchView({ el: $('#search_container') });

На событие изменения модели можно повесить функцию render() представления:

var UserView = Backbone.View.extend({
  initialize: function() {
    this.model.bind('change', _.bind(this.render, this));
  }
});

Обратите внимание, мы использовали функцию _.bind (реализацию функции bind() из Underscore.js), чтобы явно указать, что значением this будет объект представления)

Обработчики событий

Чтобы создать обработчики событий в представлении, используется свойство events. Обработчики событий могут быть связаны только с элементами DOM внутри el.


SearchView = Backbone.View.extend({
  initialize: function() {
    alert('Initialized!');
  },
  events: {
    'click input[type=button]': 'doSearch'
  },
  render: function() {
    var template = _.template($('#search_template').html(), {});
    this.$el.html(template);>
    return this;
  }
});
var searchView = new SearchView({ el: $('#search_container') });

Коллекция (Collection)

Коллекции в Backbone.js представляют собой не что иное как группы моделей. Если проводить аналогию в базой данных, то коллекция — это результат запроса содержащий несколько записей.

Определить коллекцию можно следующим образом:

var BooksCollection = Backbone.Collection.extend({  
  model: Book
});

С моделями коллекции можно совершать определенные действия, к примеру, отфильтруем модели по автору. Для этого мы создали новый метод, который принимает имя автора (тут вероятно ошибка, из кода следует, что принимает дату публикации) в качестве параметра:

var BooksCollection = Backbone.Collection.extend( {  
  model : Book,  
  old : function() {  
    return this.filter(function(book) {   
      return book.get('releaseDate') < 1900;   
   });  
  }
});

Объявить объект коллекции можно так же, как и модель:

var oBooks = new BooksCollection();
oBooks.get(0);

В данном примере мы создали объект коллекции и получили элемент коллекции с ID равным 0.

Наконец, если вам нужно получить данные коллекции с сервера, вы можете воспользоваться методом fetch(). При этом в атрибутах коллекции должен быть указан URL, откуда мы будет получать данные.

var BooksCollection = Backbone.Collection.extend( {  
  model: Books,  
  url: '/books' 
});  
  
var oBooks = new BooksCollection();  
oBooks.fetch();

Роутер (Router)

Роутер используется для маршрутизации внутри приложения.

var appRouter = Backbone.Router.extend({
  routes: {
    "": "start",
    "!/": "start",
    "!/books": "books",
  },
  start: function() { 
    // код, который должен выполняться на главной странице приложения
  },
  books: function() { 
    // код, который должен выполняться, когда URL страницы
    // http://somedomain.com/#!/books
  },
});

После того, как созданы все роутеры, в момент инициализации приложения необходимо вызвать функцию Backbone.history.start();

На тему Backbone:

Поделиться
Отправить
Отправить