Перейти к содержанию

Шаблонизаторы

В Node.js для генерации и отдачи HTML-страниц используются шаблонизаторы. Node.js шаблонизатор представляет собой специальный модуль, использующий более удобный синтаксис для формирования HTML на основе динамических данных и позволяющий разделять представление от контроллера.

Настройка Node.js шаблонизатора осуществляется заданием двух параметров:

  • views - путь к директории, в которой находятся шаблоны;
  • view engine - указание самого шаблонизатора.

Для задания этих параметров используется метод Express set().

app.set('views', './views')
app.set('view engine', 'handlebars')

Шаблонизаторов очень много, но наибольшее распространение получили Handlebars и Pug.

Handlebars

Начнем с установки Node.js handlebars.

npm install --save express-handlebars

И сразу рассмотрим пример.

app.js

const express = require('express')
const app = express()
const handlebars = require('express-handlebars')

const host = '127.0.0.1'
const port = 7000

app.engine('handlebars', handlebars({ defaultLayout: 'main' }))
app.set('views', './views')
app.set('view engine', 'handlebars')

app.get('/', (req, res) => {
  res.render('home', { title: 'Greetings form Handlebars' })
})

app.listen(port, host, function() {
  console.log(`Server listens http://${host}:${port}`)
})

views/home.handlebars

<h1>{{{title}}}</h1>

views/layouts/main.handlebars

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <title>Node js Handlebars</title>
  </head>
  <body>
    {{{body}}}
  </body>
</html>

С помощью метода engine() задается настройка Node.js handlebars, конкретно в примере указывается шаблон по умолчанию, в который будут подгружаться шаблоны страниц.

Генерация и отдача представления осуществляется с помощью метода render(), который принимает два параметра:

  • шаблон;
  • данные для шаблона в виде объекта (если необходимо).

Если директория с шаблонами не задана явно, то поиск представлений по умолчанию будет осуществляться в директории views, а макеты - в views/layouts.

Шаблоны Node.js handlebars представляют собой обычные файлы HTML в формате handlebars, в которых с помощью специального синтаксиса выводятся передаваемые данные. Для отображения значения свойства переданного объекта используется запись {{{(название свойства)}}}.

В макете /views/layouts/main.handlebars запись {{{body}}} определяет место, куда при запросе определенной страницы будет вставлено соответствующее ей представление.

Чтобы сгенерировать представление без макета, в объекте, передаваемом функции render() укажите свойство layout со значением false. Если хотите использовать макет, отличный от макета по умолчанию, просто укажите его имя. Помните, что макеты должны находиться в директории layouts директории с представлениями.

app.get('/', (req, res) => {
  res.render('home', { title: 'Greetings form Handlebars', layout: false })
})

Node.js handlebars гибкий шаблонизатор с обширным функционалом.

Кэширование

В handlebars предусмотрен механизм кэширования представлений в режиме production. Шаблонизатор самостоятельно следит за режимом запуска приложения и управляет кэшированием. Но для этого сперва необходимо активировать кэширование с помощью Express.

app.enable('view cache')

Условия

В представлениях Node.js handlebars предусмотрен механизм отображения той или иной части шаблона в зависимости от определенного условия.

app.get('/', (req, res) => {
  res.render('home', {
    title: 'Greetings form Handlebars',
    content: 'Description how to use it handlebars'
  })
})
<h1>{{title}}</h1>

{{#if content}}
<p>{{content}}</p>
{{/if}}

Циклы

Для вывода данных переданного массива в Node.js шаблонизаторе handlebars предусмотрена конструкция, аналогичная работе обычного цикла.

app.get('/', (req, res) => {
  res.render('home', {
    title: 'Greetings form Handlebars',
    advantages: ['simple', 'flexible', 'powerful']
  })
})
<h1>{{title}}</h1>

{{#if advantages}}
<p>Advantages</p>

<ul>
  {{#each advantages}}
  <li>{{this}}</li>
  {{/each}}
</ul>
{{/if}}

Частичные представления

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

partials/advantages.handlebars

<ul>
  {{#each advantages}}
  <li>{{this}}</li>
  {{/each}}
</ul>

home.handlebars

<h1>{{title}}</h1>

{{#if advantages}}
<p>Advantages</p>
{{> advantages}} {{/if}}

Вспомогательные функции

Под вспомогательными функциями в Node.js handlebars подразумеваются функции, которые могут быть вызваны прямо в представлении для обработки отображаемых данных. Такие функции могут быть определены глобально для всех шаблонов или только для одного конкретного и задаются в свойстве helpers.

app.engine(
  'handlebars',
  handlebars({
    defaultLayout: 'main',
    helpers: {
      getTitle: () => 'Greetings form Handlebars'
    }
  })
)
app.set('views', './views')
app.set('view engine', 'handlebars')

app.get('/', (req, res) => {
  res.render('home', {
    helpers: {
      getAdvantages: () => ['simple', 'flexible', 'powerful']
    }
  })
})
<h1>{{getTitle}}</h1>

<p>Advantages: {{getAdvantages}}</p>

Вспомогательные функции, определенные локально в методе render() конкретного запроса, могут использоваться только в шаблоне, обрабатываемом этим запросом.

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

Pug

Еще один популярный Node.js шаблонизатор - Pug. Сразу установим его.

npm install pug --save

И сразу пример с Node.js Pug в качестве шаблонизатора.

app.js

const express = require('express')
const app = express()

const host = '127.0.0.1'
const port = 7000

app.set('views', './views')
app.set('view engine', 'pug')

app.get('/', (req, res) => {
  res.render('main', { title: 'Greetings from Pug' })
})

app.listen(port, host, function() {
  console.log(`Server listens http://${host}:${port}`)
})

views/main.pug

html(lang="en")
  head
    title Node js Pug
    meta(charset="utf-8")
  body
    h1 #{title}

В Node.js Pug представления имеют расширение .pug и подобно шаблонизатору Handlebars генерируются с помощью метода объекта ответа render(), принимающего первым параметром имя шаблона, а вторым - данные для этого шаблона в виде объекта.

Шаблонизатор использует крайне необычный подход к построению представления. Каждая строка в файле полностью описывает одни HTML-элемента. Сначала идет имя тега, затем через пробел - его значение. Для использования в значении тега (или его атрибута) внешних данных, применяется механизм интерполяции. Так, свойство переданного объекта, значение которого необходимо использовать, заключается в #{ и }.

h1 #{title}

Если HTML-тег не указан, то по умолчанию будет использоваться div.

Атрибуты HTML-элементов задаются в следующем формате.

тег(имя*атрибута='значение*атрибута')

Вложенность тегов HTML в Node.js Pug шаблоне реализуется через отступ табуляции относительно родителя, причем эта вложенность соблюдается в файле и визуально. Для компиляции HTML-кода в одну строку без соблюдения визуальной иерархии используйте следующую запись.

p: span

//Результат: '<p><span></span></p>'

Гибкость работы с Node.js Pug обеспечивается рядом специальных инструментов и конструкций.

Переменные

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

-var title = 'New greetings from Pug'

html(lang="en")
  head
    title Node js Pug
    meta(charset="utf-8")
  body
    h1 #{title}

Условия Pug

Node.js шаблонизатор Pug для реализации условий использует конструкции, аналогичные JavaScript операторам if и switch.

Пример с if.

app.get('/', (req, res) => {
  res.render('index', {
    title: 'Greetings from Pug',
    content: 'Node js Pug description'
  })
})
html(lang="en")
  head
    title Node js Pug
    meta(charset="utf-8")
  body
    h1 #{title}

    if content
      p #{content}
    else
      p No content

Пример со switch.

app.get('/', (req, res) => {
  res.render('index', {
    title: 'Greetings from Pug',
    type: 'h3'
  })
})
html(lang="en")
  head
    title Node js Pug
    meta(charset="utf-8")
  body
    case type
      when 'h1'
        h1 #{title}
      when 'h2'
        h2 #{title}
      when 'h3'
        h3 #{title}

Циклы Pug

Отображение массива данных или вывод какой-либо части шаблона заданное количество раз осуществляется с помощью конструкций each и while.

html(lang="en")
  head
    title Node js Pug
    meta(charset="utf-8")
  body
    ol
      each vl, index in ['One', 'Two', 'Three']
        li #{vl} (#{index})

Переиспользование шаблонов

Для переиспользования представления в Node.js Pug имеется оператор include, в указанное место вставляет содержимое файла заданного шаблона.

views/index.pug

html(lang="en")
  head
    title Node js Pug
    meta(charset="utf-8")
  body
    include includes/_list.pug

views/includes/_list.pug

ol
  each vl, index in ['One', 'Two', 'Three']
    li #{vl} (#{index})

Если указанного файла не существует, то в HTML-документ значение оператора include будет вставлено обычной строкой.

Наследование

Node js Pug реализует принцип наследования для шаблонов, за которое отвечают операторы block и extends. С помощью block в представлении описывается какая-либо его часть, которая может быть заменена при наследовании (через extends) шаблона другим шаблоном. В родительском представлении блок может иметь значение по умолчанию, но если дочернее представление имеет собственную реализацию, то будет использоваться она.

app.js

app.get('/', (req, res) => {
  res.render('home')
})

views/index.pug

html(lang="en")
  head
    title Node js Pug
    meta(charset="utf-8")
  body
    block nav
      ul
        li Home
        li About
        li Contacts
    block content
    block footer

views/home.pug

extends index.pug
block nav
  ul
    li Home
    li About
    li Contacts
  block content
    div Content text
  block footer
    footer Footer information

Также Node.js Pug позволяет “расширять” значение по умолчанию, а не заменять его. Для этого имеются операторы append и prepend, которые добавляют указанное содержимое после или до значения, заданного по умолчанию.

extends index.pug
block prepend nav
  a: img(src="/assets/images/logo.svg" alt="Logo")
block content
  div Content text
block footer
  footer Footer information

Миксины

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

views/mixins/_button.pug

mixin button(label, cssClass)
  button(class =cssClass) #{label}

views/index.pug

include mixins/_button.pug
html(lang="en")
  head
    title Node js Pug
    meta(charset="utf-8")
  body
    +button('Cancel', 'red')
    +button('Send')