Сервер на Node.js - Шаблонизация (часть вторая)

Сервер на Node.js - Шаблонизация (часть вторая)

Содержание курса

  1. Начало
  2. Шаблонизация (часть первая)
  3. Шаблонизация (часть вторая)
  4. Шаблонизация (часть третья)

 

Мы установили шаблонизатор и даже создали парочку шаблонов, но пока что это "детский сад". У handlebars огромный потенциал и сегодня мы попробуем его немножечко освоить.

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

И так, для изучения синтаксиса мы возьмём сильно упрощённый сервер из прошлой статьи. Состоять он будет из 2 файлов:

server.js

// Подключаемые модули
var express = require('express');
var hbs = require("hbs");


var app = express();  // Привязываем express к нашему "приложению"


// Для шаблонов страниц
hbs.registerPartials(__dirname + "/views/templates", function() {
  app.set("view engine", "hbs");


  // Обработчик запросов
  app.use(function(req, res, next) {
    res.render('index.hbs');
  });


  app.listen(3000);   // Установка порта
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>
	</body>
</html>

 

Основная задача hbs - это динамическое формирование контента. Это мы сегодня и разберём.

Для начала немного теории - КАК и ЗАЧЕМ?

Динамическое формирование страницы подразумевает, что у нас есть один шаблон страницы (к примеру, страницы статьи) в котором прописаны основные элементы, одинаковые для всех страниц статей (шапка сайта, сайдбар, HTML разметка и т.п.). Также в этом шаблоне прописаны специальные "метки", на место которых будут вставляться уникальные данные.

Нужно это для того, чтобы не создавать отдельный файл для каждой статьи. Мы создаём один шаблон, а всю уникальную информацию о статьях храним в БД. При запросе страницы в шаблон вставляются соответствующие данные и вуаля - клиент получает нужную страницу.

Начнём.

Вставка значения на страницу

В функцию res.render(), после названия файла, передаём объект с нашими значениями в формате 'название: значение'

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    author: 'Vanyaka',
    site: 'vse-sdelano.ru',
    number: 3
  });
});

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

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Автор урока: {{author}}</p>
		<p>Специально для сайта <b>{{site}}</b></p>
		<p>Номер урока: <i>{{number}}</i></p>
	</body>
</html>

Теперь, если вы измените данные в сервере, то и страница изменится тоже (чтобы изменения подхватились необходимо перезапустить сервер: Ctrl + C и node server.js)

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

Обратите внимание: если вы попытаетесь вставить на страницу HTML код, то он будет преобразован к тексту и ничего дельного не получится. Чтобы код грамотно встроился нужно запретить экранировать HTML теги, для этого код вызывать нужно в тройных фигурных скобках:

{{{HTML текст}}} .

Пример:

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    author: 'Vanyaka',
    site: 'vse-sdelano.ru',
    number: 3,
    html: '<b>Жирный</b> <i>Курсив</i>'
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Автор урока: {{author}}</p>
		<p>Специально для сайта <b>{{site}}</b></p>
		<p>Номер урока: <i>{{number}}</i></p>
		<div>
			html: <br/>
			{{{html}}}
		</div>
	</body>
</html>

Обработка массива

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    data: ['Vanyaka', 'vse-sdelano.ru', 3]
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Автор урока: {{data.[0]}}</p>
		<p>Специально для сайта <b>{{data.[1]}}</b></p>
		<p>Номер урока: <i>{{data.[2]}}</i></p>
	</body>
</html>

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

Массивы могут быть и многомерными:

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    data: [['Vanyaka', 'Vasya'], {site: 'vse-sdelano.ru', number: 3}]
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Автор урока: {{data.[0].[0]}}</p>
		<p>Специально для сайта <b>{{data.[1].site}}</b></p>
		<p>Номер урока: <i>{{data.[1].number}}</i></p>
	</body>
</html>

Обработка массива в цикле

Мы не всегда можем знать сколько элементов будет в массиве (например кол-во статей может меняться) и неплохо было бы зациклить обработку некоторого массива. Для этого в hbs имеется аналог цикла for:

{{#each массив}}
	тело цикла
{{/each}}

Если массив одномерный, то в теле цикла значение можно вызывать через {{this}} - грубо говоря, это значит массив[i].

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    names: ['Vanyaka', 'Vasya', 'Nastya']
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Их разыскивает полиция:<p>
		{{#each names}}
			<p><b>{{this}}</b> (<i>Особо опасен!</i>)</p>
		{{/each}}
	</body>
</html>

Вы можете добавить в цикл любое кол-во элементов и все они будут обработаны.

Если массив многомерный, то внутри цикла к элементам можно обращаться по всем правилам:

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    data: [{name: 'Vanyaka', type: 'Хацкер'}, {name: 'Vasya', type: 'Киборг'}, {name: 'Nastya', type: 'На всякий случай...'}]
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Их разыскивает полиция:<p>
		{{#each data}}
			<p><b>{{this.name}}</b> (<i>{{this.type}}</i>)</p>
		{{/each}}
	</body>
</html>

В случае с многомерными массивами, this можно опустить:

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Их разыскивает полиция:<p>
		{{#each data}}
			<p><b>{{name}}</b> (<i>{{type}}</i>)</p>
		{{/each}}
	</body>
</html>

Смысл от этого никак не измениться (this здесь подразумевается сам собой). Подобные циклы могут быть любой сложности и даже вложенными - всё как положено:

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    data: [{name: 'Vanyaka', transgressions: ['Говнокод', 'Халатное отношение к учёбе']}, {name: 'Vasya', transgressions: ['Навязчивость', 'Плохой ИИ']}]
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Их разыскивает полиция:<p>
		{{#each data}}
			<div>
				<b>Имя:</b> {{name}} <br/>
				<b>Преступления:</b>
				<ul>
					{{#each transgressions}}
						<li>{{this}}</li>
					{{/each}}
				</ul>

				<br/><br/>
			</div>
		{{/each}}
	</body>
</html>

Условия

Куда же без них... Их все любят и hbs не мог обойти их стороной.

Конструкция проста как колесо:

{{#if условие}}
	код, который выполнится, если "условие" верно
{{/if}}

Пример:

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    list: [{name: 'Vanyaka', flag: true}, {name: 'Vasya', flag: false}, {name: 'Nastya', flag: true}]
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Настоящие люди:<p>
		{{#each list}}
			{{#if flag}}
				<p>{{name}}</p>
			{{/if}}
		{{/each}}
	</body>
</html>

В итоге вставятся только те имена, у которых flag равен true.

Существует и полная конструкция:

{{#if условие}}
	код 1
{{else}}
	код 2
{{/if}}

Пример:

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    list: [{name: 'Vanyaka', flag: true}, {name: 'Vasya', flag: false}, {name: 'Nastya', flag: true}]
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Наша команда:<p>
		{{#each list}}
			{{#if flag}}
				<p>{{name}} (человек)</p>
			{{else}}
				<p>{{name}} (бот)</p>
			{{/if}}
		{{/each}}
	</body>
</html>

Но есть один существенный недостаток: по дефолту в условиях нельзя прописывать сколько-нибудь сложные выражения - только true или false. Есть способы это обыграть, но это уже совсем другая история... tongue-out

Условия, точно также могут быть вложенными.

server.js

// Обработчик запросов
app.use(function(req, res, next) {
  res.render('index.hbs', {
    mainFlag: false,
    list: [{name: 'Vanyaka', flag: true}, {name: 'Vasya', flag: false}, {name: 'Nastya', flag: true}]
  });
});

index.hbs

<!DOCTYPE html>
<html>
	<head>
		<title>Синтаксис handlebars</title>
		<meta charset="utf-8">
	</head>

	<body>
		<h1>Синтаксис handlebars</h1>

		<p>Наша команда:<p>
		{{#if mainFlag}}
			{{#each list}}
				{{#if flag}}
					<p>{{name}} (человек)</p>
				{{else}}
					<p>{{name}} (бот)</p>
				{{/if}}
			{{/each}}
		{{else}}
			<p>У вас недостаточно прав для получения <b>этой информации</b>...</p>
		{{/if}}
	</body>
</html>

Обратите внимание: если элемент условия не будет найден (в данном случае mainFlag), то никакой ошибки не будет и выполнится блок {{else}}. Так что тестируйте свои условия на разных значениях.

На этом всё, исходники всех примеров лежат здесь.

P.S. конечно же, мы рассмотрели не все возможности handlebars, но для начала нам хватит и этого.laughing

TEXT.RU - 89.53%

Поделиться ссылкой:

Добавить комментарий

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

Системное сообщение