Статьи

Использование встроенных партиалов и декораторов с Handlebars 4.0

Handlebars — одна из наиболее широко используемых библиотек JavaScript для рендеринга как на стороне клиента, так и на стороне сервера. Он реализует спецификацию усов, но добавляет дополнительный соус, чтобы упростить работу с шаблонами. Если вы новичок в Handlebars и хотите узнать больше, я предлагаю вам ознакомиться с моим курсом Pluralsight по шаблонированию JavaScript с Handlebars, чтобы узнать, как начать работу.

Версия Handlebars 4.0 появилась в сентябре 2015 года и принесла с собой две основные новые функции: Inline Partials и Decorators . В этой статье мы рассмотрим обе функции, объясним их синтаксис и когда вы должны их использовать. В конце концов, вы должны чувствовать себя комфортно, используя обе функции, чтобы поднять свою игру шаблонов на новый уровень!

Inline Partials

Частицы — это общая концепция шаблонов, не уникальная для руля. Идея заключается в том, чтобы создать шаблоны, которые могут быть повторно использованы, разделить их на собственный файл ( частичный ), а затем использовать их в разных шаблонах. В Partials вы можете подумать, что это простой инструмент для модуляции ваших шаблонов.

В Handlebars Partials может быть не самой удобной структурой для работы. Прежде всего, все частичные являются глобальными. Это означает, что этот инструмент может работать для вашего приложения, но нехватка контроля над ним может стать проблемой в больших приложениях. Во-вторых, частичные имена должны быть зарегистрированы с использованием JavaScript. Многие прекомпиляторы или загрузчики шаблонов будут обрабатывать это для вас, вызывая Handlebars.registerPartial() Наконец, частичные элементы должны быть отделены от шаблонов, в которых они используются. Это может быть благом, если ваши шаблоны большие, но это также может затруднить разработчикам полное понимание вывода шаблона. Им нужно будет переключаться между множеством разных файлов, прежде чем понимать полный вывод.

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

С Inline Partials , Handlebars, наконец, раскрывает истинный потенциал Partials , позволяя вам отбросить JavaScript и необходимость разделять партиалы на отдельные файлы. Встроенные партиалы определяются внутри ваших шаблонов в синтаксисе Handlebars. Для их регистрации не требуется JavaScript. Вы просто объявляете частичное и используете его. Кроме того, они не глобальны, а имеют ограниченную область. Это означает, что после того, как вы объявили Inline Partial в своем шаблоне, он может использоваться только в текущей области и любой области ниже.

Принимая решение об использовании Inline Partial или обычного Partial, поищите небольшие многократно используемые фрагменты HTML-кода, которые имеют одно из следующих свойств:

  • Они слишком малы, чтобы заслуживать того, чтобы быть в их частичном файле.
  • Они используются (или могут быть использованы) только в контексте одного шаблона.

Использование Inline Partials

Теперь давайте посмотрим на встроенный частичный синтаксис и использование.

Вот как вы объявляете Inline Partial. Во-первых, возьмите код, который вы хотите быть вашим частичным.

 <li>I'm iteration #{{number}}</li>

Затем оберните его новым встроенным синтаксисом, передав один аргумент, который является именем частичного.

 {{#* inline "iterationCount"}}
    <li>I'm iteration #{{number}}</li>
{{/inline}}

Теперь вы можете использовать этот фрагмент в шаблоне Handlebars, где он был объявлен. Вот полный пример.

 {{#* inline "iterationCount"}}
    <li>I'm iteration #{{number}}</li>
{{/inline}}

{{#each someArray}}
    {{> iterationCount}}
{{/each}}

Пример простых партиалов

Учитывая предыдущее объяснение, следующий шаг — понять, как мы будем использовать Partials до того, как у нас будут встроенные Partials. Давайте предположим, что мы начнем с этого шаблона:

 // template.hbs
<h1>Hello {{firstName}} {{lastName}}</h1>
<ul>
    {{#each clients}}
        <li>{{firstName}} {{lastName}}</li>
    {{/each}}
</ul>

Повторение {{firstName}} {{lastName}} Задача, которую необходимо выполнить, состоит в том, чтобы извлечь этот шаблон в частичное, поэтому давайте посмотрим, что нам нужно сделать, чтобы его достичь.

Прежде всего, вы создаете файл JavaScript, например someFile.js

 Handlebars.registerPartial('fullName', '{{firstName}} {{lastName}}');

Тогда в вашем шаблоне Handlebars вы можете иметь:

 <h1>Hello {{> fullName}}</h1>
<ul>
    {{#each clients}}
        <li>{{> fullName}}</li>
    {{/each}}
</ul>

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

Пример Inline Partials

Теперь давайте возьмем предыдущий пример и решим его с помощью Inline Partials. В следующем примере вы заметите несколько вещей:

  • Все в одном файле и на одном языке.
  • Частичная область действия шаблона означает, что у вас может быть другой формат «полного имени» в другом файле.
  • Сохраняйте те же преимущества, что и обычные партиалы, такие как устранение избыточности.

Ниже приведено полное решение с использованием Inline Partials:

 // template.hbs
{{#* inline "fullName"}}{{firstName}} {{lastName}}{{/inline}}
<h1>Hello {{> fullName}}</h1>
<ul>
    {{#each clients}}
        <li>{{> fullName}}</li>
    {{/each}}
</ul>

Декораторы

Во введении к этой статье я упомянул еще одну важную особенность Handlebars версии 4.0 — Decorators .

Декораторы позволяют «декорировать» функцию программы Handlebars и изменять состояния перед рендерингом шаблона. Основная цель — дать вам возможность использовать «выходные данные» метаданных, чтобы добавить функциональность в ваши шаблоны. Реализация основана на предложении Yehuda Katz JavaScript Decorator для ES6 . Во многих отношениях Decorators в Handlebars предоставляют вам помощника для вспомогательных функций на более фундаментальном уровне. Фактически, до их появления вы, возможно, использовали помощников для достижения того, что сейчас элегантно делается декораторами.

Чтобы понять, как декораторы подходят для рендеринга шаблонов Handlebars, давайте посмотрим, как Handlebars компилирует шаблоны. «Танец на руле», как мне это нравится, звучит примерно так:

  1. Получение шаблона
  2. Компиляция шаблона
  3. Рендеринг вывода

На этих трех этапах второй выполняется путем вызова функции Handlebars.compile Он принимает шаблон в виде строки и компилирует его, возвращая функцию, которую затем можно вызвать с некоторыми контекстными данными (третий шаг сверху). Каждый блок в вашем шаблоне Handlebars создает одну из этих скомпилированных функций, а основная возвращаемая функция вызывает их по мере необходимости для визуализации вашего вывода.

Декораторы вставляют себя в эти скомпилированные функции с областью действия блока, предоставляя вам контроль над выполнением некоторых функций перед визуализацией блока. Что вы делаете с ним, зависит от вас, но возвращаемое значение, которое ожидает Decorator, — это функция, которая будет отображать выходные данные шаблона.

Прежде чем рассматривать аргументы функции Decorator, давайте рассмотрим простой пример.

Использование декораторов

Декораторы зарегистрированы в JavaScript, как помощники и частичные (хотя и не встроенные!). Вот пример этого:

 Handlebars.registerDecorator('shhh', function(program, props, container, context) {
    var isLoud = program().trim() === 'loud';
    if (isLoud) {
        return function() { return ''; };
    } else {
        return program;
    }
});

В приведенном выше примере мы рассмотрим программную функцию Handlebars (я обычно называю это «скомпилированная функция» ). Если программа возвращает «громко», то мы перезапишем ее функцией, которая возвращает пустую строку. В противном случае мы вернем нормальную функцию программы.

Посмотрим, как будет использоваться этот декоратор:

 loud
{{*shhh}}

В этом примере шаблона функция оригинальной программы вернет «громко» (декораторы не выводят). И результат этого шаблона при визуализации будет:

Это верно, просто пустая строка.

Функция, целью которой является визуализация «оформленного» шаблона, который возвращается из «shhh» Decorator, возвращает пустую строку. Эта функция возвращается на основе правдивости «громко».

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

 quiet
{{*shhh}}

Вывод при рендеринге этого шаблона будет:

 quiet

Поскольку программа не соответствовала «громко», она была пропущена, а не перезаписана.

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

Аргументы функции декоратора

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

Вот полная сигнатура функции для функции Decorator:

 function(program, props, container, context)

Возвращаемое значение функции декоратора

Декораторы должны возвращать значение функции или ложное значение ( undefinednullfalse Любая возвращаемая строка или объект вызовет исключение. Возвращенная функция будет использована для визуализации готовой строки Handlebars. Если возвращается undefined

program

Это скомпилированная функция Handlebars, которая передает данные и возвращает отображаемую строку. Вы можете изменить аргументы, возвращаемое значение или настроить контекст при вызове функции. Верните этот программный аргумент, чтобы рендеринг проходил через декоратор. Вы также можете «перезаписать» аргумент программы, вернув другую функцию.

props

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

container

Это текущий контейнер времени выполнения Handlebars. Он содержит все партиалы, помощники и контекстные данные и может быть изменен (как вы увидите в примере ниже).

context

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

Форматирование денег в руле Pre-4.0

Чтобы продемонстрировать Decorators в реальном мире, давайте взглянем на пример использования шаблона, с которым вы, возможно, знакомы: форматирование денег. Мы хотим найти простой способ динамического форматирования заданного значения для данной валюты. Рули обеспечивают некоторые существующие механизмы для решения этой проблемы. Давайте посмотрим, как решить эту проблему с помощью функций Handlebars до 4.0.

Сначала мы создаем помощника для форматирования денег. Помощник примет значение для форматирования и валюту в качестве аргументов:

 //someFile.js
Handlebars.registerHelper('formatMoneyHelper', function(value, currency) {
    switch(currency) {
        case 'USD':
            return new Handlebars.safeString('$' + value + 'USD');
        case 'EUR':
            return new Handlebars.safeString('€' + value + 'EUR');
    }
});

Теперь мы можем использовать этот помощник в шаблоне.

 //template.hbs

Starting amount: {{formatMoneyHelper this.start this.format}}
Ending amount: {{formatMoneyHelper this.end this.format}}
Profit/Loss: {{formatMoneyHelper this.net this.format}}

Мы ожидаем, что наши данные будут в следующем формате:

 {
    start: 12.30,
    end: 15.30,
    net: 3.00,
    format: 'USD'
}

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

Форматирование денег с помощью декораторов в руле 4.0

Лучший способ отформатировать деньги - это иметь более простого помощника, который просто берет значение. Он должен уже понимать, в какой валюте должны быть отформатированы деньги. Динамически это сделать было бы непросто с помощниками, поэтому давайте воспользуемся декораторами, чтобы найти более простое решение.

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

 function formatUSD(value) {
    return new Handlebars.safeString('$' + value + 'USD');
}

function formatEUR(value) {
    return new Handlebars.safeString('€' + value + 'EUR');
}

Handlebars.registerDecorator('activateFormatter', function(program, props, container, context) {
    var moneyHelper,
        format = context.args[0] || context.data.root.format;

    switch(format) {
        case "USD":
            moneyHelper = formatUSD;
            break;
        case "EUR":
            moneyHelper = formatEUR;
            break;
        default:
            console.log('Money format not set. Please set before rendering template.');
            moneyHelper = function() {};
    }

    container.helpers = {
        formatMoneyHelper: moneyHelper
    };
});

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

Далее давайте посмотрим, как мы можем использовать этот декоратор в нашем шаблоне:

 //template.hbs

{{* activateFormatter}}

Starting amount: {{formatMoneyHelper this.start}}
Ending amount: {{formatMoneyHelper this.end}}
Profit/Loss: {{formatMoneyHelper this.net}}

Это будет использовать свойство format в нашем объекте контекста, чтобы установить функцию formatUSD в качестве нашей вспомогательной функции formatMoneyHelper. Мы также можем переопределить его, используя этот синтаксис:

 {{* activateFormatter "EUR"}}

Реализация с использованием Decorators более элегантна, тестируема и позволяет вам контролировать форматирование текущего блока внутри вашего шаблона.

Декораторы невероятно мощные, и приведенный выше пример - просто взгляд на то, что можно сделать.

Выводы

Надеемся, что эта статья вдохновила вас использовать Inline Partials и Decorators в ваших собственных проектах, использующих Handlebars. Вы видели, как встроенные партиалы полезны для определения партиалов в вашем шаблоне и уменьшения количества накладных расходов JavaScript для регистрации партиалов. Более того, вы видели, что они идеально подходят для небольших повторяющихся фрагментов разметки. С другой стороны, декораторы позволяют вам изменять существующую функцию блочной программы Handlebars и дают вам контроль над временем выполнения Handlebars перед выполнением. Они идеально подходят, чтобы связываться с контекстными данными или помощниками.

Поэтому Inline Partials и Decorators являются мощным дополнением к уже существенному инструменту для фронт-энда разработки.

А теперь иди и укрась свои шаблоны руля с Inline Partials!