Handlebars. Руководство к действию

от автора

Данная статья содержит в себе описание основных возможностей шаблонизатора Handlebars и является свободным переводом его официальной документации. Итак, поехали…



С помощью Handlebars вы сможете построить эффективные семантические шаблоны. Шаблоны Handlebars во многом совместимы с шаблонами Mustache — в большинстве случаев они взаимозаменяемы. Полные сведения можно найти по этой ссылке.

Выражения

Для начала работы с Handlebars необходимо подключить файл handlebars.js:

<script src="js/handlebars.js"></script> 

Шаблоны Handlebars выглядят как обычный HTML, со встроенными handlebars-выражениями.

Самое простое handlebars-выражение представляет собой простой идентификатор:

{{some_contents}} 

Идентификатором может быть любой символ Unicode за исключением следующих:

Пробел ! " # % & ' ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~ 

Вы можете вставить шаблон Handlebars в ваш HTML-код, включив его в тэг <script />:

<script id="entry-template" type="text/x-handlebars-template">   <div class="entry">     <h1>{{title}}</h1>   </div> </script> 

В JavaScript шаблон компилируется с помощью Handlebars.compile:

var source   = $("#entry-template").html(); var template = Handlebars.compile(source); 

Возможна также предварительная компиляция шаблона, что приведет к меньшей ресурсоемкости, что может быть очень важно при работе с мобильными устройствами.

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

var context = { title: "Собаке Качалова" }; var html    = template(context); 

Мы получим HTML-код:

<div class="entry">   <h1>Собаке Качалова</h1> </div> 

Handlebars-выражения могут иметь пути, разделенные точками. Они позволяют искать свойства, вложенные ниже текущего контекста:

<div class="entry">   <h1>{{title}}</h1>   <h2>{{author.name}}</h2> </div> 

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

Этот шаблон будет работать со следующим контекстом:

var context = {   title: "Собаке Качалова",   author: {     id: 47,     name: "Сергей Есенин"   } }; 

Пути Handlebars также могут включать ../ сегменты, позволяющие указать путь относительно родительского контекста. С ними мы столкнемся, когда будем рассматривать блоковые хелперы.

Handlebars экранирует выражения, помещенные в двойные скобки {{ }}. Чтобы избежать этого, необходимо поместить выражение в тройные скобки {{{ }}}. Чтобы в будущем при написании генерирующего HTML-код хэлпера избежать экранирования возвращаемого им результата, мы будем возвращать new Handlebars.SafeString(result)

Хелперы

Handlebars-хелпер представляет собой простой идентификатор, за которым следуют ноль или более параметров (через пробел). Каждый параметр представляет собой handlebars-выражение. Параметром хелпера может также являться простая строка, число или логическое значение. Хелпер производит определенные операции с параметрами и возвращает HTML код.

{{{link "Подробнее..." poem.url}}} 

Handlebars-хелперы могут быть доступны в шаблоне из любого контекста.

<div>   <h1>{{poem.title}}</h1>   {{link "Подробнее..." poem.url}} </div> 

Вы можете зарегистрировать хелпер с помощью метода Handlebars.registerHelper. При использовании следующего контекста и хелпера:

var context = {   poem: {     title: "Собаке Качалова",     url: "Sobake_Kachalova.html"   } }; Handlebars.registerHelper('link', function(text, url) {   url = Handlebars.escapeExpression(url);      //экранирование выражения   text = Handlebars.escapeExpression(text);   return new Handlebars.SafeString("<a href='" + url + "'>" + text + "</a>"); }); 

Получим следующий результат:

<div>   <h1>Собаке Качалова</h1>   <a href='Sobake_Kachalova.html'>Подробнее...</a> </div> 

Handlebars-хелперам также можно передать последовательность пар ключ-значение после всех непарных параметров. Ключи должны быть простыми идентификаторами, а значения — handlebars-выражениями (т.е. значения могут быть идентификаторами, путями, или строками).

{{link "Подробнее..." href=poem.url class="poem"}} 

Регистрация хелпера:

Handlebars.registerHelper('link', function(text, options) {   console.log(options.hash['href']);   //значение, лежащее в poem.url   console.log(options.hash['class']); //"poem"   return new Handlebars.SafeString("<a href=\"" + options.hash['href'] + "\">" + Handlebars.escapeExpression(text) + "</a>"); }); 

Потенциально может возникнуть конфликт имен между хелперами и полями данных (скажем, у нас используются в одном контексте handlebars-выражение {{name}} и хелпер {{name}}). Handlebars предлагает нам следующую возможность разрешения этого конфликта:

<p>{{./name}} or {{this/name}} or {{this.name}}</p> 

Любое из вышеперечисленных handlebars-выражений вызовет поле данных {{name}} в текущем контексте, а не хелпер с тем же самым именем.

Блоковые хелперы

Блоковые хелперы позволяют определять пользовательские итераторы, а также другую функциональность, с помощью которой можно вызвать переданный блок в новом контексте. Блоковый хелпер записывается следующим образом:

{{#helper_name}}some_block{{/helper_name}} 

При регистрации хелпера параметры в Handlebars.registerHelper передаются в том порядке, в котором они были переданы хелперу пользователем. Вслед за всеми указанными пользователем параметрами следует параметр options. Он имеет следующие свойства:

1) options.fn — содержит функцию, которая ведет себя как обычный скомпилированный шаблон Handlebars. В качестве параметра функция принимает контекст и возвращает строку.

Пример 1. Давайте определим блоковый хелпер, который изменяет разметку обернутого в него текста:

<div class="body">   {{#bold}}{{body}}{{/bold}} </div> 

Регистрация:

Handlebars.registerHelper('bold', function(options) {   return '<div class="mybold">' + options.fn(this) + '</div>'; }); 

Так как содержание блокового хелпера экранируется при вызове options.fn(context), Handlebars не экранирует результат, возвращаемый блоковым хелпером. Если это сделать, то внутреннее содержание будет экранировано дважды!

Здесь в качестве параметра функции мы передали текущий контекст (this). Давайте укажем другой контекст, передав его хелперу как параметр:

Пример 2.

<div class="entry"> {{author}} {{#with poem}}   <div class="title">{{title}}</div>   <div class="author">{{../author}}</div>   <div class="year">{{year}}</div> {{/with}} </div> 

Выполнить этот шаблон мы могли бы со следующим JSON, имеющим вложенные в объект poem ключи title и year:

{   author: "Сергей Есенин",   poem: {     title: "Собаке Качалова",     year: 1925   } } 

Регистрация:

Handlebars.registerHelper('with', function(context, options) {   console.log(context);   //{title: "Собаке Качалова", year: 1925}   return options.fn(context); }); 

Мы получим HTML-код:

<div class="entry">   Сергей Есенин   <div class="title">Собаке Качалова</div>   <div class="author">Сергей Есенин</div>   <div class="year">1925</div> </div> 

Обратим внимание, что в этом примере мы использовали сегмент ../ для указания пути к свойству author, находящемуся вне контекста poem.

Пример 3. Давайте напишем итератор, создающий обертку <ul /> и вкладывающий в нее каждый передаваемый ему блок как элемент <li />.

{{#list nav}}   <a href="{{url}}">{{title}}</a> {{/list}} 

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

{   nav: [     { url: "http://www.museum-esenin.ru/biography", title: "Биография Сергея Есенина" },     { url: "http://www.fedordostoevsky.ru/biography", title: "Биография Ф. М. Достоевского" },   ] } 

Регистрация хелпера:

Handlebars.registerHelper('list', function(context, options) {   var ret = "<ul>";    for(var i=0, j=context.length; i<j; i++) {     ret = ret + "<li>" + options.fn(context[i]) + "</li>";   }    return ret + "</ul>"; }); 

Мы получим HTML-код:

<ul>   <li><a href="http://www.museum-esenin.ru/biography">Биография Сергея Есенина</a></li>   <li><a href="http://www.fedordostoevsky.ru/biography">Биография Ф. М. Достоевского</a></li> </ul> 

2) options.inverse — функция используется при работе с управляющими структурами Handlebars. Управляющие структуры обычно не изменяют текущий контекст — вместо этого они решают, вызвать ли блок, основываясь на значении переданного параметра.

{{#if isActive}}   <img src="minus.gif" alt="Active"> {{else}}   <img src="plus.gif" alt="Inactive"> {{/if}} 

Handlebars возвращает блок, следующий за {{else}}, через функцию options.inverse:

Handlebars.registerHelper('if', function(conditional, options) {   if(conditional) {     return options.fn(this);   } else {     return options.inverse(this);   } }); 

3) options.hash — содержит последовательность пар ключ-значение, передаваемых хелперу после всех непарных параметров.

Пример. Давайте вернемся к хелперу list и сделаем возможным добавление любого количества атрибутов создаваемой нами обертки <ul />.

{{#list nav id="nav-bar" class="top"}}   <a href="{{url}}">{{title}}</a> {{/list}} 

Handlebars передает парные параметры в options.hash, где они хранятся как ключи-значения объекта.

Регистрация хелпера:

Handlebars.registerHelper('list', function(context, options) {   var attrs = [];   for (key in options.hash) {     attrs.push(key + '="' + options.hash[key] + '"');   }   return "<ul " + attrs.join(" ") + ">" + context.map(function(item) {     return "<li>" + options.fn(item) + "</li>";   }).join("\n") + "</ul>"; }); 

Мы получим HTML-код:

<ul class="top" id="nav-bar">   <li><a href="http://www.museum-esenin.ru/biography">Биография Сергея Есенина</a></li>   <li><a href="http://www.fedordostoevsky.ru/biography">Биография Ф. М. Достоевского</a></li> </ul> 

Хеш-аргументы предоставляют мощную возможность передать блочному хелперу много дополнительных параметров без сложностей, связанных с позициями аргументов.

Встроенные хелперы

1) if — используйте этот хелпер для вывода блока по условию.

<div class="entry">   {{#if author}}     <h1>{{firstName}} {{lastName}}</h1>   {{else}}     <h1>Автор неизвестен</h1>   {{/if}} </div> 

2) unless — используйте этот хелпер как обратный хелперу if. Блок будет выведен, если выражение вернет ложное значение.

<div class="entry">   {{#unless license}}   <h3 class="warning">ВНИМАНИЕ: Эта запись не имеет лицензии!</h3>   {{/unless}} </div> 

3) each — используйте этот хелпер для перебора списков. Внутри блока Вы можете использовать this для ссылки на элемент списка.

<ul class="writers_list">   {{#each writers}}     <li>{{@index}}: {{this}}</li>   {{else}}     <li>Список пуст</li>   {{/each}} </ul> 

Этот шаблон может быть использован в следующем контексте:

{   writers: [     "А. С. Пушкин",     "Ф. М. Достоевский",     "Сергей Есенин"   ] } 

В результате получим:

<ul class="writers_list">   <li>0: А. С. Пушкин</li>   <li>1: Ф. М. Достоевский</li>   <li>2: Сергей Есенин</li> </ul> 

Блок, следующий за секцией {{else}}, выводится только когда список пуст.

4) with — используйте этот хелпер для сдвига контекста секции handlebars-шаблона.

<div class="entry">   <h1>{{title}}</h1>   {{#with author}}     <h2>{{firstName}} {{lastName}}</h2>   {{else}}     <h2>Автор неизвестен</h2>   {{/with}} </div> 

Этот шаблон может быть использован в следующем контексте:

{   title: "Собаке Качалова",   author: {     firstName: "Сергей",     lastName: "Есенин"   } } 

5) log — позволяет логировать состояние контекста во время выполнения шаблона.

{{log "Фамилия: " lastName "; Имя: " firstName}} 

Делегируется в Handlebars.logger.log, который может быть переопределен для выполнения пользовательского логирования.
Более подробная информация о встроенных хелперах с примерами находится по этой ссылке.

Повторное использование шаблонов (Partials)

Partials позволяют повторно использовать код путем создания общих шаблонов. Partials — это обычные handlebars-шаблоны, которые могут быть непосредственно вызваны через другие шаблоны.

Чтобы использовать Partial, его необходимо сначала зарегистрировать через Handlebars.registerPartial:

Handlebars.registerPartial('myPartial', '{{name}}') 

Partial может быть предварительно скомпилирован — в таком случае предварительно скомпилированный шаблон передается в качестве второго параметра.

Вызов Partial:

{{> myPartial }} 

Partial выполняется в текущем контексте. Имеется также возможность выполнить Partial в пользовательском контексте, передавая контекст при вызове Partial:

{{> myPartial myOtherContext }} 

Более подробные сведения о Partials можно получить, перейдя по этой ссылке.

ссылка на оригинал статьи http://habrahabr.ru/post/273581/


Комментарии

Добавить комментарий

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