[Из песочницы] Handlebars. Руководство к действию

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

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


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




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

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

{{some_contents}}


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

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


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




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

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


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

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

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


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

Собаке Качалова


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

{{title}}

{{author.name}}


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

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

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


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

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

Хелперы


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

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


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

{{poem.title}}

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


Вы можете зарегистрировать хелпер с помощью метода 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("" + text + "");
});


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

Собаке Качалова

Подробнее...


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("" + Handlebars.escapeExpression(text) + "");
});


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

{{./name}} or {{this/name}} or {{this.name}}


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

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


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

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


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

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

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

{{#bold}}{{body}}{{/bold}}


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

Handlebars.registerHelper('bold', function(options) {
  return '
' + options.fn(this) + '
'; });


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

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

Пример 2.

{{author}} {{#with poem}}
{{title}}
{{../author}}
{{year}}
{{/with}}


Выполнить этот шаблон мы могли бы со следующим 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-код:

Сергей Есенин
Собаке Качалова
Сергей Есенин
1925


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

Пример 3. Давайте напишем итератор, создающий обертку

    и вкладывающий в нее каждый передаваемый ему блок как элемент
  • .

    {{#list nav}}
      {{title}}
    {{/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 = "
      "; for(var i=0, j=context.length; i" + options.fn(context[i]) + ""; } return ret + "
    "; });


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

    
    
    


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

    {{#if isActive}}
      Active
    {{else}}
      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 и сделаем возможным добавление любого количества атрибутов создаваемой нами обертки

      .

      {{#list nav id="nav-bar" class="top"}}
        {{title}}
      {{/list}}
      
      


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

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

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


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

      
      
      


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

      {{#if author}}

      {{firstName}} {{lastName}}

      {{else}}

      Автор неизвестен

      {{/if}}


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

      {{#unless license}}

      ВНИМАНИЕ: Эта запись не имеет лицензии!

      {{/unless}}


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

        {{#each writers}}
      • {{@index}}: {{this}}
      • {{else}}
      • Список пуст
      • {{/each}}


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

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


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

      • 0: А. С. Пушкин
      • 1: Ф. М. Достоевский
      • 2: Сергей Есенин


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

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

      {{title}}

      {{#with author}}

      {{firstName}} {{lastName}}

      {{else}}

      Автор неизвестен

      {{/with}}


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

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


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

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


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

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

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


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

      Вызов Partial:

      {{> myPartial }}
      
      


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

      {{> myPartial myOtherContext }}
      
      


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

      © Habrahabr.ru