Handlebars.js с Backbone.js

Интеграция Handlebars в Backbone

Backbone.js предоставляет минималистичную архитектуру для создания клиентских веб-приложений, основываясь на Models, Collections, Views и Routers. Для генерации HTML-шаблонов часто используют Handlebars.js — лёгкий и быстрый движок шаблонов, позволяющий создавать чистый и читаемый код интерфейса.

Интеграция Handlebars с Backbone происходит через связывание представлений (Views) с шаблонами. В типичном подходе создаётся HTML-шаблон с использованием Handlebars-синтаксиса, а затем View в Backbone компилирует этот шаблон и рендерит его с данными из модели или коллекции.

Компиляция шаблонов

Шаблоны Handlebars можно хранить как в отдельных файлах, так и внутри скриптов в HTML:

<script id="item-template" type="text/x-handlebars-template">
  <div class="item">
    <h2>{{title}}</h2>
    <p>{{description}}</p>
  </div>
</script>

В Backbone View шаблон компилируется следующим образом:

var ItemView = Backbone.View.extend({
  tagName: 'div',
  className: 'item-container',

  template: Handlebars.compile($('#item-template').html()),

  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  }
});

Ключевые моменты:

  • template: Handlebars.compile(...) — компилирует шаблон один раз при создании View.
  • this.model.toJSON() — преобразует данные модели в обычный объект для передачи в шаблон.
  • Возврат this из метода render() позволяет осуществлять цепочку вызовов.

Рендеринг коллекций

При работе с коллекциями часто используется отдельный View для контейнера коллекции и отдельный View для каждого элемента:

var ListView = Backbone.View.extend({
  tagName: 'ul',

  initialize: function() {
    this.listenTo(this.collection, 'add remove reset', this.render);
  },

  render: function() {
    this.$el.empty();
    this.collection.each(function(item) {
      var itemView = new ItemView({ model: item });
      this.$el.append(itemView.render().el);
    }, this);
    return this;
  }
});

Особенности:

  • listenTo гарантирует, что View автоматически обновляется при изменении коллекции.
  • Каждое добавление элемента коллекции создаёт отдельный дочерний View.
  • Метод empty() предотвращает дублирование элементов при повторном рендеринге.

Использование хелперов Handlebars

Handlebars поддерживает хелперы, которые позволяют добавлять логику отображения внутри шаблонов. Например:

Handlebars.registerHelper('uppercase', function(str) {
  return str.toUpperCase();
});

Использование в шаблоне:

<p>{{uppercase title}}</p>

Применение в Backbone:

var ItemView = Backbone.View.extend({
  template: Handlebars.compile($('#item-template').html()),

  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  }
});

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

Частичные шаблоны

Handlebars поддерживает partials — повторно используемые фрагменты шаблонов. В Backbone это удобно для составных интерфейсов:

Handlebars.registerPartial('itemPartial', $('#item-template').html());

var ListView = Backbone.View.extend({
  template: Handlebars.compile(
    '{{#each items}}{{> itemPartial}}{{/each}}'
  ),

  render: function() {
    this.$el.html(this.template({ items: this.collection.toJSON() }));
    return this;
  }
});

Особенности частичных шаблонов:

  • Упрощают поддержку повторяющихся блоков.
  • Позволяют передавать данные напрямую через контекст.
  • Частицы можно комбинировать для создания сложных интерфейсов.

Динамическое обновление данных

Для обновления интерфейса при изменении модели используется listenTo или привязка событий модели к View:

var ItemView = Backbone.View.extend({
  template: Handlebars.compile($('#item-template').html()),

  initialize: function() {
    this.listenTo(this.model, 'change', this.render);
  },

  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  }
});

Важные моменты:

  • Любое изменение данных модели автоматически вызывает рендеринг.
  • Это обеспечивает реактивность интерфейса без ручного обновления DOM.
  • Поддержка событий add, remove, reset для коллекций позволяет строить полностью динамичные списки.

Интеграция с Backbone.Router

Handlebars-шаблоны удобно использовать при маршрутизации для отрисовки страниц:

var AppRouter = Backbone.Router.extend({
  routes: {
    'items/:id': 'showItem'
  },

  showItem: function(id) {
    var item = itemsCollection.get(id);
    var view = new ItemView({ model: item });
    $('#content').html(view.render().el);
  }
});

Принципы работы:

  • Каждый маршрут может рендерить отдельный View с соответствующим шаблоном.
  • Использование Handlebars позволяет держать шаблоны изолированными от логики маршрутизации.
  • Такой подход упрощает поддержку многостраничных интерфейсов в одностраничных приложениях (SPA).

Производительность и оптимизация

При работе с большим количеством элементов рекомендуется:

  • Компилировать шаблоны один раз и переиспользовать.
  • Использовать частичные шаблоны для повторяющихся элементов.
  • Обновлять только изменившиеся элементы, а не весь DOM.
  • Кэшировать HTML-фрагменты при необходимости.

Handlebars с Backbone.js создаёт мощное сочетание для построения структурированных и динамичных интерфейсов, позволяя отделить данные, логику и представление, сохраняя код чистым и поддерживаемым.