Spec-Zone.ru › Handlebars.js

Помощники блоков

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

Основные блоки

В демонстрационных целях определим помощника блока, который вызывает блок так, как будто помощника не существует.
<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{#noop}}{{body}}{{/noop}}
  </div>
</div>
Помощник noop (аббревиатура от "без действия") получит хеш опций. Этот хеш опций содержит функцию (options.fn), которая ведет себя как обычный скомпилированный шаблон Handlebars. В частности, функция будет принимать контекст и возвращать строку.
Handlebars.registerHelper('noop', function(options) {
  return options.fn(this);
});
Handlebars всегда вызывает помощников с текущим контекстом в качестве this, поэтому вы можете вызвать блок с this, чтобы оценить блок в текущем контексте.
Любые помощники, определенные таким образом, будут иметь приоритет над полями, определенными в контексте. Чтобы получить доступ к полю, замаскированному помощником, можно использовать ссылку на путь. В примере выше поле с именем noop объекта контекста будет ссылаться следующим образом:
{{./noop}}

Вариант основного блока

Для лучшей иллюстрации синтаксиса определим еще один помощник блока, который добавляет разметку к обернутому тексту.
<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{#bold}}{{body}}{{/bold}}
  </div>
</div>
Помощник bold добавит разметку, чтобы сделать текст полужирным. Как и прежде, функция будет принимать контекст в качестве входных данных и возвращать строку.
Handlebars.registerHelper('bold', function(options) {
  return new Handlebars.SafeString(
      '<div class="mybold">'
      + options.fn(this)
      + '</div>');
});

Помощник with

Помощник with демонстрирует, как передать параметр вашему помощнику. Когда помощник вызывается с параметром, он вызывается с любым контекстом, который передал шаблон.
<div class="entry">
  <h1>{{title}}</h1>
  {{#with story}}
    <div class="intro">{{{intro}}}</div>
    <div class="body">{{{body}}}</div>
  {{/with}}
</div>
Вы можете найти такой помощник полезным, если раздел вашего объекта JSON содержит глубоко вложенные свойства, и вы хотите избежать повторения имени родительского элемента. Приведенный выше шаблон может быть полезен с JSON, подобным:
{
  title: "First Post",
  story: {
    intro: "Before the jump",
    body: "After the jump"
  }
}
Реализация помощника, подобного этому, очень похожа на реализацию помощника noop. Помощники могут принимать параметры, и параметры оцениваются так же, как выражения, используемые непосредственно внутри блоков {{mustache}}.
Handlebars.registerHelper('with', function(context, options) {
  return options.fn(context);
});
Параметры передаются помощникам в том порядке, в котором они передаются, за которыми следует хеш опций.

Простые итераторы

Распространенным случаем использования помощников блоков является их использование для определения пользовательских итераторов. На самом деле, все встроенные помощники Handlebars определены как обычные помощники блоков Handlebars. Давайте рассмотрим, как работает встроенный помощник each.
<div class="entry">
  <h1>{{title}}</h1>
  {{#with story}}
    <div class="intro">{{{intro}}}</div>
    <div class="body">{{{body}}}</div>
  {{/with}}
</div>
<div class="comments">
  {{#each comments}}
    <div class="comment">
      <h2>{{subject}}</h2>
      {{{body}}}
    </div>
  {{/each}}
</div>
В данном случае мы хотим вызвать блок, переданный each, один раз для каждого элемента в массиве comments.
Handlebars.registerHelper('each', function(context, options) {
  var ret = "";

  for(var i=0, j=context.length; i<j; i++) {
    ret = ret + options.fn(context[i]);
  }

  return ret;
});
В данном случае мы итерируемся по элементам переданного параметра, вызывая блок один раз с каждым элементом. По мере итерации мы формируем строковый результат, а затем возвращаем его.
Этот шаблон можно использовать для реализации более сложных итераторов. Например, давайте создадим итератор, который создаёт оболочку <ul>, и оборачивает каждый полученный элемент в <li>.
{{#list nav}}
  <a href="{{url}}">{{title}}</a>
{{/list}}
Вы оцените этот шаблон, используя что-то вроде этого в качестве контекста:
{
  nav: [
    { url: "http://www.yehudakatz.com", title: "Katz Got Your Tongue" },
    { url: "http://www.sproutcore.com/block", title: "SproutCore Blog" },
  ]
}
Помощник похож на исходный помощник each.
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>";
});
Использование библиотеки, такой как underscore.js или SproutCore's runtime library, сделает это немного более красивым. Например, вот как это может выглядеть с использованием библиотеки SproutCore's runtime:
Handlebars.registerHelper('list', function(context, options) {
  return "<ul>" + context.map(function(item) {
    return "<li>" + options.fn(item) + "</li>";
  }).join("\n") + "</ul>";
});

Условные операторы

Еще одним распространенным случаем использования помощников блоков является оценка условных выражений. Как и в случае с итераторами, встроенные конструкции управления Handlebars, if и unless, реализованы как обычные помощники Handlebars.
{{#if isActive}}
  <img src="star.gif" alt="Active">
{{/if}}
Конструкции управления, как правило, не изменяют текущий контекст, а вместо этого принимают решение о вызове блока на основе некоторой переменной.
Handlebars.registerHelper('if', function(conditional, options) {
  if(conditional) {
    return options.fn(this);
  }
});
При написании условного оператора вы часто захотите сделать так, чтобы шаблоны могли предоставить блок HTML, который ваш помощник должен вставить, если условие не выполняется. Handlebars решает эту проблему, предоставляя общую функциональность else для помощников блоков.
{{#if isActive}}
  <img src="star.gif" alt="Active">
{{else}}
  <img src="cry.gif" alt="Inactive">
{{/if}}
Handlebars предоставляет блок для фрагмента else как options.inverse. Вам не нужно проверять существование фрагмента else: Handlebars автоматически определит его и зарегистрирует функцию "noop".
Handlebars.registerHelper('if', function(conditional, options) {
  if(conditional) {
    return options.fn(this);
  } else {
    return options.inverse(this);
  }
});
Handlebars предоставляет дополнительную метаданные помощникам блоков, прикрепляя их как свойства хеша опций. Читайте дальше для получения дополнительных примеров.
Условные операторы также могут быть объединены, включая последующий вызов помощника в части else.
{{#if isActive}}
  <img src="star.gif" alt="Active">
{{else if isInactive}}
  <img src="cry.gif" alt="Inactive">
{{/if}}
Необязательно использовать тот же помощник в последующих вызовах, помощник unless может использоваться в части else, как и любой другой помощник. Когда значения помощников различны, закрывающая фигурная скобка должна соответствовать открытому имени помощника.

Аргументы хеша

Как и обычные помощники, помощники блоков могут принимать необязательный хеш в качестве последнего аргумента. Давайте пересмотрим помощника list и сделаем его возможным для нас добавить любое количество дополнительных атрибутов в элемент <ul>, который мы создадим.
{{#list nav id="nav-bar" class="top"}}
  <a href="{{url}}">{{title}}</a>
{{/list}}
Handlebars предоставляет конечный хеш как options.hash. Это упрощает принятие переменного числа параметров, а также необязательного хеша. Если шаблон не предоставляет аргументов хеша, Handlebars автоматически передаст пустой объект ({}), поэтому вам не нужно проверять существование аргументов хеша.
Handlebars.registerHelper('list', function(context, options) {
  var attrs = Object.keys(options.hash).map(function(key) {
    return key + '="' + options.hash[key] + '"';
  }).join(" ");

  return "<ul " + attrs + ">" + context.map(function(item) {
    return "<li>" + options.fn(item) + "</li>";
  }).join("\n") + "</ul>";
});
Аргументы хеша представляют собой мощный способ предложить ряд необязательных параметров помощнику блока без сложности, возникающей из-за позиционных аргументов.

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

Например, при итерации по списку вы можете предоставить текущий индекс как частную переменную.

{{#list array}}
  {{@index}}. {{title}}
{{/list}}
Handlebars.registerHelper('list', function(context, options) {
  var out = "<ul>", data;

  if (options.data) {
    data = Handlebars.createFrame(options.data);
  }

  for (var i=0; i<context.length; i++) {
    if (data) {
      data.index = i;
    }

    out += "<li>" + options.fn(context[i], { data: data }) + "</li>";
  }

  out += "</ul>";
  return out;
});
Частные переменные, предоставленные через опцию data, доступны во всех дочерних областях видимости.
К частным переменным, определенным в родительских областях видимости, можно получить доступ через запросы с путями. Чтобы получить доступ к полю index родительского итератора, можно использовать @../index.
Убедитесь, что вы создаете новую таблицу данных в каждом помощнике, который присваивает свои собственные данные. В противном случае помощники, находящиеся ниже по иерархии, могут непредвиденно изменить переменные выше по иерархии.
Также убедитесь, что поле data определено до попытки взаимодействия с существующим объектом данных. Поведение частных переменных условно компилируется, и некоторые шаблоны могут не создавать это поле.

Параметры блока

Новая функция в Handlebars 3.0 — это возможность получать именованные параметры от поддерживающих помощников.
{{#each users as |user userId|}}
  Id: {{userId}} Name: {{user.name}}
{{/each}}
В этом конкретном примере, user будет иметь то же значение, что и текущий контекст, а userId будет иметь значение индекса для итерации.
Это позволяет вложенным помощникам избегать конфликтов имен, которые могут возникать с частными переменными.
{{#each users as |user userId|}}
  {{#each user.book as |book bookId|}}
    User Id: {{userId}} Book Id: {{bookId}}
  {{/each}}
{{/each}}
Ряд встроенных помощников поддерживает параметры блоков, и любой пользовательский помощник может предоставить их через поле опций blockParams.
Handlebars.registerHelper('block-params', function() {
  var args = [],
      options = arguments[arguments.length - 1];
  for (var i = 0; i < arguments.length - 1; i++) {
    args.push(arguments[i]);
  }

  return options.fn(this, {data: options.data, blockParams: args});
});
{{#block-params 1 2 3 as |foo bar baz|}}
  {{foo}} {{bar}} {{baz}}
{{/block-params}}
Реализует помощник, который позволяет объявлять именованные переменные внутри данного блока. В данном примере на выводе будет 1 2 3.
Помощники могут определять количество параметров блоков, на которые ссылается шаблон, по полю options.fn.blockParams, которое представляет собой целое число. Это значение соответствует количеству параметров блока, на которые может ссылаться дочерний шаблон. Параметры, превышающие это количество, никогда не будут ссылаться и могут быть безопасно опущены помощником, если это необходимо. Это необязательно, и любые дополнительные параметры, переданные в шаблон, будут проигнорированы.

Сырые блоки

Сырые блоки доступны для шаблонов, которым требуется обработка необработанных блоков mustache.
{{{{raw-helper}}}}
  {{bar}}
{{{{/raw-helper}}}}
выполнит помощник raw-helper без интерпретации содержимого.
Handlebars.registerHelper('raw-helper', function(options) {
  return options.fn();
});
будет отображать
{{bar}}

© 2011–2017 by Yehuda Katz
Licensed under the MIT License.
https://handlebarsjs.com/block_helpers.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API