#10 – Использование шаблонизатора
В ходе урока мы рассмотрим использование шаблонизатора ejs для формирования HTML файлов. За счет EJS вы сможете передавать данные в HTML, обрабатывать их, создавать условия, циклы и прочие конструкции.
Видеоурок
Полезные ссылки:
- Пакетный менеджер NPM ;
- Официальный сайт EJS шаблонизатора .
Шаблонизаторы полезны и существуют во многих языках программирования. Их основная задача – передача данных из языка программирования в HTML-шаблон. Получив данные мы можем оперировать с ними как с обычными переменными: сравнивать, выводить на экран, добавлять к ним значения и так далее. Для Node JS существует шаблонизатор EJS , который выполняет задачу на отлично.
Для работы с ним выполните его подключения и установите пакет в проект. Для этого используйте команду npm install ejs .
В главном файле укажите шаблонизатор что вы используете:
const express = require('express'); const app = express(); // Указываем шаблонизатор app.set('view engine', 'ejs');
Все файлы-шаблоны должны храниться в папке views. Для отображения шаблонов на странице используйте метод render() .
app.get('/', (req, res) => < // Вывод HTML-шаблона "index" res.render('index', ); >)
Для создания шаблона сделайте файл с расширением .ejs . В него поместите обычный HTML-код и в определенных местах используйте разметку шаблонизатора. Для использования специальной разметки помещайте код в блоках: . Более детально про различный вывод данных вы можете прочесть на официальном сайте EJS .
HTML и CSS
Для создания разметки и стилей необходимо понимать принципы написания HTML и CSS. Вы можете пройти полный курс по HTML и полный курс по CSS у нас на сайте. Также вы можете вкратце ознакомится с технологиями в наших больших видео уроках.
Изучение HTML за 45 минут:
Изучение CSS за 45 минут:
Шаблонизатор LoDash
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
В этой главе мы рассмотрим шаблонизацию – удобный способ генерации HTML по «шаблону» и данным.
Большинство виджетов, которые мы видели ранее, получают готовый HTML/DOM и «оживляют» его. Это типичный случай в сайтах, где JavaScript – на ролях «второго помощника». Разметка, CSS уже есть, от JavaScript, условно говоря, требуются лишь обработчики, чтобы менюшки заработали.
Но в сложных интерфейсах разметка изначально отсутствует на странице. Компоненты генерируют свой DOM сами, динамически, на основе данных, полученных с сервера или из других источников.
Зачем нужны шаблоны?
Ранее мы уже видели код Menu , который сам создаёт свой элемент:
function Menu(options) < // . приведены только методы для генерации DOM . function render() < elem = document.createElement('div'); elem.className = "menu"; var titleElem = document.createElement('span'); elem.appendChild(titleElem); titleElem.className = "title"; titleElem.textContent = options.title; elem.onmousedown = function() < return false; >; elem.onclick = function(event) < if (event.target.closest('.title')) < toggle(); >> > function renderItems() < var items = options.items || []; var list = document.createElement('ul'); items.forEach(function(item) < var li = document.createElement('li'); li.textContent = item; list.appendChild(li); >); elem.appendChild(list); > // . >
Понятен ли этот код? Очевидно ли, какой HTML генерируют методы render , renderItems ?
С первого взгляда – вряд ли. Нужно как минимум внимательно посмотреть и продумать код, чтобы разобраться, какая именно DOM-структура создаётся.
…А что, если нужно изменить создаваемый HTML? …А что, если эта задача досталась не программисту, который написал этот код, а верстальщику, который с HTML/CSS проекта знаком отлично, но этот JS-код видит впервые? Вероятность ошибок при этом зашкаливает за все разумные пределы.
К счастью, генерацию HTML можно упростить. Для этого воспользуемся библиотекой шаблонизации.
Пример шаблона
Шаблон – это строка в специальном формате, которая путём подстановки значений (текст сообщения, цена и т.п.) и выполнения встроенных фрагментов кода превращается в DOM/HTML.
Пример шаблона для меню:
Как видно, это обычный HTML, с вставками вида .
Для работы с таким шаблоном используется специальная функция _.template , которая предоставляется фреймворком Lodash, её синтаксис мы подробно посмотрим далее.
Пример использования _.template для генерации HTML с шаблоном выше:
// сгенерировать HTML, используя шаблон tmpl (см. выше) // с данными title и items var html = _.template(tmpl)(< title: "Сладости", items: [ "Торт", "Печенье", "Пирожное" ] >);
Значение html в результате:
Этот код гораздо проще, чем JS-код, не правда ли? Шаблон очень наглядно показывает, что в итоге должно получиться. В отличие от кода, в шаблоне первичен текст, а вставок кода обычно мало.
Давайте подробнее познакомимся с _.template и синтаксисом шаблонов.
Holy war detected!
Способов шаблонизации и, в особенности, синтаксисов шаблонов, примерно столько же, сколько способов поймать льва в пустыне. Иначе говоря… много.
Эта глава – совершенно не место для священных войн на эту тему.
Далее будет более полный обзор типов шаблонных систем, применяемых в JavaScript, но начнём мы с _.template , поскольку эта функция проста, быстра и демонстрирует приёмы, используемые в целом классе шаблонных систем, активно используемых в самых разных JS-проектах.
Синтаксис шаблона
Шаблон представляет собой строку со специальными разделителями, которых всего три:
Код между разделителями будет выполнен «как есть»
– для вставки expr как HTML
Переменная или выражение внутри будет вставлено «как есть». Например: вставит значение переменной title , а вставит 4 .
– для вставки expr как текста
Переменная или выражение внутри будет вставлено «как текст», то есть с заменой символов < >& » ‘ на соответствующие HTML-entities.
Например, если expr содержит текст
, то при в результат попадёт, в отличие от , не HTML-тег
, а текст <br> .
Функция _.template
Для работы с шаблоном в библиотеке LoDash есть функция _.template(tmpl, data, options) .
tmpl Шаблон. options Необязательные настройки, например можно поменять разделители.
Эта функция запускает «компиляцию» шаблона tmpl и возвращает результат в виде функции, которую далее можно запустить с данными и получить строку-результат.
// Шаблон var tmpl = _.template('; // Результат подстановки alert( tmpl(data) ); //Пример выше похож на операцию «поиск-и-замена»: шаблон просто заменил на значение свойства data.title .
Но возможность вставки JS-кода делает шаблоны сильно мощнее.
Например, вот шаблон для генерации списка от 1 до count :
-
\ \
- \ %>\
- 1
- 2.
-
, потом выполнился код for , который последовательно сгенерировал элементы списка, и затем список был закрыт
Хранение шаблона в документе
Шаблон – это многострочный HTML-текст. Записывать его прямо в скрипте – неудобно.
Один из альтернативных способов объявления шаблона – записать его в HTML, в тег с нестандартным type , например "text/template" :
Если type не знаком браузеру, то содержимое такого скрипта игнорируется, однако оно доступно при помощи innerHTML :
var template = document.getElementById('menu-template').innerHTML;
В данном случае выбран type="text/template" , однако подошёл бы и любой другой нестандартный, например text/html . Главное, что браузер такой скрипт никак не обработает. То есть, это всего лишь способ передать строку шаблона в HTML.
Полный пример цикла с подключением библиотеки и шаблоном в HTML:
Как работает функция _.template?
Понимание того, как работает _.template , очень важно для отладки ошибок в шаблонах.
Как обработка шаблонов устроена внутри? За счёт чего организована возможность перемежать с текстом произвольный JS-код?
Оказывается, очень просто.
Вызов _.template(str) разбивает строку str по разделителям и, при помощи new Function создаёт на её основе JavaScript-функцию. Тело этой функции создаётся таким образом, что код, который в шаблоне оформлен как – попадает в неё «как есть», а переменные и текст прибавляются к специальному временному «буферу», который в итоге возвращается.
Взглянем на пример:
var compiled = _.template(" "); alert( compiled );
Функция compiled , которую вернул вызов _template из этого примера, выглядит примерно так:
function(obj) < obj || (obj = <>); var __t, __p = '', __e = _.escape; with(obj) < \ __p += '' + ((__t = (title)) == null ? '' : __t) + '
'; > return __p >
Она является результатом вызова new Function("obj", "код") , где код динамическим образом генерируется на основе шаблона:
- Вначале в коде идёт «шапка» – стандартное начало функции, в котором объявляется переменная __p . В неё будет записываться результат.
- Затем добавляется блок with(obj) < . >, внутри которого в __p добавляются фрагменты HTML из шаблона, а также переменные из выражений . Код из копируется в функцию «как есть».
- Затем функция завершается, и return __p возвращает результат.
При вызове этой функции, например compiled() , она получает объект данных как obj , здесь это , и если внутри with(obj) < .. >обратиться к title , то по правилам конструкции with это свойство будет получено из объекта.
Можно и без with
Конструкция with является устаревшей, но в данном случае она полезна.
Так как функция создаётся через new Function("obj", "код") то:
- Она работает в глобальной области видимости, не имеет доступа к внешним локальным переменным.
- Внешний use strict на такую функцию не влияет, то есть даже в строгом режиме шаблон продолжит работать.
Если мы всё же не хотим использовать with – нужно поставить второй параметр – options , указав параметр variable (название переменной с данными).
alert( _.template(" ", ) );
function(menu) < var __t, __p = ''; __p += '' + ((__t = (menu.title)) == null ? '' : __t) + '
'; return __p >
При таком подходе переменная title уже не будет искаться в объекте данных автоматически, поэтому нужно будет обращаться к ней как .
Кеширование скомпилированных шаблонов
Чтобы не компилировать один и тот же шаблон много раз, результаты обычно кешируют.
Например, глобальная функция getTemplate("menu-template") может доставать шаблон из HTML, компилировать, результат запоминать и сразу отдавать при последующих обращениях к тому же шаблону.
Меню на шаблонах
Рассмотрим для наглядности полный пример меню на шаблонах.
JS для создания меню:
var menu = new Menu(< title: "Сладости", // передаём также шаблоны template: _.template(document.getElementById('menu-template').innerHTML), listTemplate: _.template(document.getElementById('menu-list-template').innerHTML), items: [ "Торт", "Пончик", "Пирожное", "Шоколадка", "Мороженое" ] >); document.body.appendChild(menu.getElem());
function Menu(options) < var elem; function getElem() < if (!elem) render(); return elem; >function render() < var html = options.template(< title: options.title >); elem = document.createElement('div'); elem.innerHTML = html; elem = elem.firstElementChild; elem.onmousedown = function() < return false; >elem.onclick = function(event) < if (event.target.closest('.title')) < toggle(); >> > function renderItems() < if (elem.querySelector('ul')) return; var listHtml = options.listTemplate(< items: options.items >); elem.insertAdjacentHTML("beforeEnd", listHtml); > function open() < renderItems(); elem.classList.add('open'); >; function close() < elem.classList.remove('open'); >; function toggle() < if (elem.classList.contains('open')) close(); else open(); >; this.getElem = getElem; this.toggle = toggle; this.close = close; this.open = open; >
Здесь два шаблона. Первый мы уже разобрали, посмотрим теперь на список ul/li :
Если разбить шаблон для списка элементов по разделителям, то он будет таким:
Вот функция, которую возвратит _.template(tmpl) для этого шаблона:
-
\n '; items.forEach(function(item) < __p += '\n
- ' + __e(item) + // экранирование функцией _.escape '\n '; >); __p += '\n
Как видно, она один-в-один повторяет код и вставляет текст в переменную __p . При этом выражение в обёрнуто в вызов _.escape, который заменяет спецсимволы HTML на их текстовые варианты.
Отладка шаблонов
Что, если в шаблоне ошибка? Например, синтаксическая. Конечно, ошибки будут возникать, куда же без них.
Шаблон компилируется в функцию, ошибка будет либо при компиляции, либо позже, в процессе её выполнения. В различных шаблонных системах есть свои средства отладки, _.template тут не блистает.
Но и здесь можно кое-что отладить. При ошибке, если она не синтаксическая, отладчик при этом останавливается где-то посередине «страшной» функции.
Попробуйте сами запустить пример с открытыми инструментами разработчика и включённой опцией «остановка при ошибке»:
В шаблоне допущена ошибка, поэтому отладчик остановит выполнение.
В Chrome картина будет примерно такой:
Библиотека LoDash пытается нам помочь, подсказать, в каком именно шаблоне произошла ошибка. Ведь из функции это может быть неочевидно.
Для этого она добавляет к шаблонам специальный идентификатор sourceURL, который служит аналогом «имени файла». На картинке он отмечен красным.
По умолчанию sourceURL имеет вид /lodash/template/source[N] , где N – постоянно увеличивающийся номер шаблона. В данном случае мы можем понять, что эта функция получена при самой первой компиляции.
Это, конечно, лучше чем ничего, но, как правило, его имеет смысл заменить sourceURL на свой, указав при компиляции дополнительный параметр sourceURL :
. var compiled = _.template(tmpl, ); .
Попробуйте запустить исправленный пример и вы увидите в качестве имени файла /template/menu-template .
Не определена переменная – ошибка
Кстати говоря, а в чём же здесь ошибка?
…А в том, что переменная items не передана в шаблон. При доступе к неизвестной переменной JavaScript генерирует ошибку.
Самый простой способ это обойти – обращаться к необязательным переменным через obj , например . Тогда в случае undefined просто ничего не будет выведено. Но в данном случае реакция совершенно адекватна, так как для меню список опций items является обязательным.
Итого
Шаблоны полезны для того, чтобы отделить HTML от кода. Это упрощает разработку и поддержку.
В этой главе подробно разобрана система шаблонизации из библиотеки LoDash:
- Шаблон – это строка со специальными вставками кода или переменных , .
- Вызов _.template(tmpl) превращает шаблон tmpl в функцию, которой в дальнейшем передаются данные – и она генерирует HTML с ними.
В этой главе мы рассмотрели хранение шаблонов в документе, при помощи с нестандартным type . Конечно, есть и другие способы, можно хранить шаблоны и в отдельном файле, если шаблонная система или система сборки проектов это позволяют.
Шаблонных систем много. Многие основаны на схожем принципе – генерации функции из строки, например:
Есть и альтернативный подход – шаблонная система получает «образец» DOM-узла и клонирует его вызовом cloneNode(true) , каждый раз изменяя что-то внутри. В отличие от подхода, описанного выше, это будет работать не с произвольной строкой текста, а только и именно с DOM-узлами. Но в некоторых ситуациях у него есть преимущество.
Такой подход используется во фреймворках:
Обзор шаблонизаторов JavaScript
Шаблонизаторы являются отличным инструментом для создания веб-приложений с более чистым и простым кодом. Ниже представлены наиболее популярные шаблонизаторы JavaScript.
Mustache.JS
Mustache.JS - это логический шаблонный синтаксис. Его можно использовать для HTML, конфигурационных файлов, исходного кода - чего угодно. Он работает путем расширения тегов в шаблоне, используя значения, предоставленные в хэше или объекте.
Transparency
Transparency - это минимальный шаблонизатор для jQuery. Он отображает объекты JSON на элементы DOM с нулевой конфигурацией. Просто вызовите .render().
Hogan.js
Hogan.js - это шаблонизатор JS 3.4k, разработанный в Twitter. Используйте его как часть вашего упаковщика ресурсов для предварительной компиляции шаблонов или включите его в браузер для обработки динамических шаблонов. Если вы разрабатываете с Node.js, просто используйте NPM, чтобы добавить пакет Hogan.
HandlebarsJS
HandlebarsJS - обеспечивает необходимую мощность, позволяющую эффективно создавать семантические шаблоны без каких-либо разочарований. Handlebars в значительной степени совместим с шаблонами Mustache. В большинстве случаев можно поменять Mustache с помощью Handlebars и продолжить использовать текущие шаблоны.
Jade Language
Jade - это движок HTML шаблонов, в основном используемый для серверных шаблонов в NodeJS.
Nunjucks
Nunjucks - это богатый и мощный язык шаблонов с наследованием блоков, автоэкранированием, макросами, асинхронным управлением и многим другим.
15 шаблонизаторов для фронтенд-разработки
Число JS-библиотек ни в коей мере не уменьшается; наоборот, оно растёт с каждым днём. Когда мы доходим до приложений JS, лучшим выбором оказываются шаблоны, чем полноценные библиотеки, потому что это приводит к более чистому базовому коду и лучшему процессу работы с ними.
Не так давно я писал, что вы могли бы попробовать написать свою библиотеку, когда придёт время. Шаблонизаторы же требуют несколько больших навыков и понимания языка, с которым вы работаете, поэтому лучше полагаться на любой шаблонизатор из имеющихся в списке ниже.
Их список можно найти в Википедии, там отлично сравниваются движки для разных языков программирования для веба, но там действительно не фокусируются на одном языке, поэтому я хотел бы посмотреть, как много движков можно перечислить для Javascript.
Если вы разрабатываете на Javascript, то узнаете ряд движков, но можно узнать и о некоторых новых. Я с удовольствием продолжу этот список вместе, и надеюсь, что он вас порадует.
ICanHaz.js
Очень простая библиотека для работы с шаблонами Mustache, другой, более быстрый движок. С ним можно определять фрагменты шаблонов в тегах скриптов с type=”text/html” и вызывать их через id, с валидацией.
Hogan.js
Twitter стремится быть частью опенсорс-сообщества. Hogan.js можно использовать как компоновщик промежуточных шаблонов, для компиляции их заранее, чтобы браузер обрабатывал эти шаблоны динамически.
Содержит то же, что и Mustache, но делает всё быстрее и эффективнее.
Handlebars.js
Handlebars — расширение шаблонизатора Mustache, созданный Крисом Ванстратом (Chris Wanstrath). Эти шаблонизаторы — имеют языки, не перегруженные логикой, разделяющие код и представление, совпадающие с нашими лучшими ожиданиями.
mustache.js
Это — самый популярный шаблонизатор сейчас в мире, и почти каждая библиотека этой категории так или иначе проистекают и идейно перекликаются с ним. Документацию очень легко прочитать, понять, и настоятельно рекомендуется использовать — он прекрасно запускается на многих языках программирования, что обеспечивает уровень популярности для него выше среднего.
Transparency
Transparency — клиентский движок шаблонизации, связывающий данные в DOM. Пишется на нём просто, понятно, простой нативный HTML и такой же JS. Нет необходимости изучать синтаксис шаблонов, всё очевидно и просто в использовании.
doT.js
Хорошо подходит для Node.js-сообщества. Быстрый, малоразмерный, без зависимостей. Героически добился баланса скорости и гибкости. (Во многом унаследовал качества Underscore.js-шаблонизатора (компонента этой библиотеки — перев.)).
Walrus
В современных веб-приложениях участвует много логики представления. Эта логика не относится к коду приложения и моделям, это — уровень представления. Язык шаблонизатора — хорошее место для неё.
Эта цель преследуется так концентрированно, что скорость шаблонизации не приоритетна; скорее, Walrus ориентирован на облегчение разработки шаблонов веб-приложений.
chibi.js
Chibi даёт всё для экономии траффика и времени для отображения шаблона, небольшая и лёгкая библиотека, которая поможет лучше шаблонизировать приложение. Больше фокусируется на CSS вместо использования анимации. (Дословная «вода» автора — перев.)
templayed.js
Это — самый маленький шаблонизатор, с которым вы столкнётесь, гарантированно (Nano — перев.). Он построен на основе Mustache, прост в использовании и понимании. Сайт имеет большой демо-пример, в котором можно запускать и тестировать код.
ECT
Подобно templayed, ECT тоже имеет демо-страницы установки на сайте, с которыми можно «поиграться» и понаблюдать живые результаты. Он сделан для скорости, и заявляет о себе как о самом быстром шаблонизаторе для JS (построен на Coffeescript). Совместим с Node.js и имеет понятный синтаксис. На Github есть бенчмарки и модульные тесты, показывающие эффективность этой библиотеки.
Pithy.js
Имеется внутренний DSL для генерации HTML в JavaScript. Это отлично для небольших фронтенд-проектов, но не рекомендуется для тяжёлых HTML-страниц.
T.js
T.js использует простую структуру данных Javascript для представления данных HTML / XML.
Nunjucks
созданный в Mozilla, Nunjucks сделан для нуждающихся в производительности и гибкости из-за возможности расширять пользовательскую библиотеку плагинов и функций.
Jade
Jade рассчитан прежде всего для серверных шаблонов в node.js, но может работать во многих других средах. Он сделан только для XML-подобных документов (HTML, RSS, . ), поэтому не используйте его для оформления простого текста, markdown, CSS и подобных документов.
Dust.js
Dust расширяет Mustache и предлагает высокое качество исполнения по сравнению с другими решениями из этого списка. Содержит очень простой и понятный API.
Движки шаблонизации Javascript
Я не пытался приводить примеры, потому что множество ссылок на официальные страницы содержат демонстрации.
Надеюсь, что вы смогли открыть для себя новые варианты для вашего следующего проекта. Уверен, что много альтернатив не упомянуто, но использование перечисленных ощущается больше всего.
- "Pure — Simple and ultra-fast templating tool to generate HTML from JSON data
- Dust.js is used by PayPal, and default in their Kraken.js framework.
- Swig — A simple, powerful, and extendable JavaScript Template Engine.
- Twig — JS implementation of the Twig Templating Language
- EJS Embedded JavaScript templates for node