Mustache – простой в изучении, но в тоже время очень популярный шаблонизатор с внушительным колличеством языков, которые его поддерживают (Ruby, JavaScript, Python, Erlang, PHP, Perl, Objective-C, Java, .NET, Android, C++, Go, Lua, ooc, ActionScript, ColdFusion, Scala, Clojure, Fantom, D, node.js, CoffeeScript.)
Мы будем пользоваться Mustache совместно с JavaScript. Скачайте Mustache и подключите его к своей web-странице. Типичный Mustache-шаблон выглядит так:
Приветствую вас, {{name}}.
Вы только что выиграли {{value}} доллариков!
{{#in_ca}}
Это примерно {{taxed_value}} долларов после уплаты налогов.
{{/in_ca}}
Структура данных:
{
"name": "Крис",
"value": 10000,
"taxed_value": 10000 - (10000 * 0.4),
"in_ca": true
}
Вот, что мы получим в итоге:
Приветствую вас, Крис.
Вы только что выиграли 10000 доллариков!
Это примерно 6000.0 долларов после уплаты налогов.
Чтобы то, что мы все проделываем не казалось мистикой, перейдем к теории.
Типы тегов в Mustache
Теги в Mustache обозначаются двойными фигурными скобками, например: {{person}}
, {{#person}}
. В обоих примерах мы говорим о person как о ключах? или ключевых тэгах. Давайте поговорим о различных типах тегов..
Переменные
Переменные - основной и самый простой тип тега в Mustache. Тег {{name}} в базовом шаблоне будет пытаться найти ключ имени в текущем контексте. Если ключ имени не найден, родительские контексты будут проверяться рекурсивно. Если достигнут верхний контекст и ключ имени так и не найден, ничего рендериться не будет.
Значения переменных отображаются HTML-безопасным образом, т.е. все HTML теги заменяются на их кодированные эквиваленты. Для отображения HTML-кода без изменений используйте тройные фигурные скобки, вместо двойных: {{{name}}}
.
Также можно использовать & для отмены экранирования переменной: {{& name}}. Этим можно воспользоваться при изменении Ограничителей тегов (подробнее в разделе Изменение Ограничителей тегов).
По умолчанию, отсутствующая переменная возвращает пустую строку. Если вас это не устраивает, настройте это правило в библиотеке Mustache. Ruby версия Mustache поддерживает повышение исключение в этой ситуации, например:
Шаблон:
* {{name}}
* {{age}}
* {{company}}
* {{{company}}}
Зададим данные для этого шаблона. Обратите внимание, что мы не стали указывать в объекте свойство age. Сейчас что-то будет)
{
"name": "Крис",
"company": "GitHub"
}
Результат нашей работы приведен ниже. Вы заметили, что в консоли ошибки нет, а там, где должен быть указан возраст Криса - пустая строка?
* Крис
*
* <b>GitHub</b>
* GitHub
Секции
Секции рендерят блоки с текстом один, или более раз, в зависимости от значения ключа в текущем контексте. Секции открываются тегом и закрывающтя тегом . Поведение секции определяется значением ключа: cекция отображается, если соответствующая ей переменная имеет булевый тип и ее значение равно true, либо эта переменная является непустым списком. Проиллюстрируем это на примере. Наш шаблон:
Показано.
{{#person}}
А теперь скрыто!
{{/person}}
Данные для вывода:
{
"person": false
}
Результат:
Показано.
Непустые списки
Если секции соответствует непустой список, то секция отображается для каждого элемента этого списка. При этом контекстом для отображения содержимого секции становится очередной элемент. Напишите такой простенький шаблон:
{{#repo}}
<b>{{name}}</b>
{{/repo}}
А для него следующие данные:
{
"repo": [
{ "name": "Шурик" },
{ "name": "Вася" },
{ "name": "Толя" }
]
}
В результате получим:
Шурик
Вася
Толя
В некоторых реализациях (JavaScript например), есть возможность отобразить список значений базовых типов (строк, чисел), указав в качестве имени переменной {{.}}. Таким образом, наш шаблон мы могли бы записать так:
{{#repo}}
<b>{{.}}</b>
{{/repo}}
Данные представить чуть более понятнеей и компактней:
{
"name": ["Шурик", "Вася", "Толя"]
}
И получить тоже самое.
Лямбды
Если значение представляет собой вызываемый объект (функция или лямбда), он будет вызываться и передавать блок текста. Передаваемый текст представляет собой неотрендеренный блок символов. {{tags}} необходимо будет расширить - lambda сделает это самостоятельно. В этом случае вы можете реализовать фильтры или кэширование.
Возьмем и напишем такой шаблон:
{{#wrapped}}
{{name}} звучит гордо!
{{/wrapped}}
И приготовим для него следующие данные:
{
"name": "Вилли",
"wrapped": function() {
return function(text, render) {
return "" + render(text) + ""
}
}
}
Получаем:
<b>Вилли звучит гордо!</b>
Неошибочные значения
Если значение является неошибочным, но не является списком, оно будет использовано в качестве контекста для одиночного рендеринга блока.
Возьмем вот такой шаблон:
{{#person?}}
Здорова, {{name}}!
{{/person?}}
Данные для вывода будут такими:
{
"person?": { "name": "Джон" }
}
Вот, что мы получим на выходе:
Здорова, Джон!
Инвертированные секции
Инвертированной секцией называется секция, открывающаяся тегом {{^имя_секции}}
, а заканчивающаяся - {{/имя_секции}}
. В то время как секции могут быть использованы для визуализации текста один, или несколько раз, в зависимости от значения ключа, инвертированные участки могут отображать текст, как только при обратном значению ключа. То есть, они будут отображаться, если ключ не существует, является ложным, или список пустой.
Приведем пример, чтобы вам было понятнее. Шаблон:
{{#repo}}
<b>{{name}}</b>
{{/repo}}
{{^repo}}
Нет данных :(
{{/repo}}
Данные:
{
"repo": []
}
В результате получим:
Нет данных :(
Комментарии
Последовательность начинающаяся с !
считается комментарием и игнорируется.
<h1>Сегодня{{! меня игнорируют}}.</h1>
Это будет отрендерено следующим образом:
<h1>Сегодня.</h1>
Комментарии могут содержать символы новой строки.
Обособленные фрагменты
Обособленные фрагменты открываются тегом {{<имя фрагмента}}
, а закрываются - {{/имя фрагмента}}
.
Обособленные фрагменты рендерятся во время выполнения (в отличие от компиляции), поэтому возможно появление рекурсивных частных значений. Таким способом избегают зацикливания.
Обособленные фрагменты также наследуют контекст вызова, тогда как в [ERB](https://ru.wikipedia.org/wiki/ERuby) может быть вот что:
<%= partial :next_more, :start => start, :size => size %>
Для Mustache требуется только это:
{{> next_more}}
Почему? Потому что файл next_more.mustache наследует размер и методы запуска от вызывающего контекста.
Таким образом, вы можете рассматривать частные значения, такие как включения, импорты, расширения шаблонов, встроенные шаблоны, или подшаблоны, даже несмотря на то, что в буквальном смысле это не так. Например, рассмотрим этот шаблон и обособленный фрагмент:
base.mustache:
<h2>Names</h2>
{{#names}}
{{> user}}
{{/names}}
user.mustache:
<strong>{{name}}</strong>
Можно считать одиночным расширенным шаблоном:
<h2>Names</h2>
{{#names}}
<strong>{{name}}</strong>
{{/names}}
Изменение Ограничителей тегов
Можно изменить ограничители тегов с {{}}
на другую последовательность символов, не содержащую пробелы и символ =
. Рассмотрим следующий пример:
* {{default_tags}}
{{=<% %>=}}
* <% erb_style_tags %>
<%={{ }}=%>
* {{ default_tags_again }}
Здесь у нас есть список с тремя пунктами. Первый пункт использует стиль ограничителей тегов по умолчанию ({{ }}
), второй использует уже другой стиль (<% %>
), а третий возвращается к исходному стилю. Это может быть полезно для таких языков, как TeX, где двойные фигурные скобки могут возникнуть в тексте и ими неудобно будет пользоваться для разметки.
На этом наше изучение шаблонизатора Мustache подошло к концу. На последок оставляю вам небольшой пример работы c Мustache на тот случай, если что-то осталось непонятно. Удачи!