Введение
На прошлых вебинарах с Димой Белицким мы сверстали простую страницу следуя БЭМ-методологии: написали HTML и CSS, немного декларативного JavaScript, а также настроили сборку с помощью gulp.
В этом вебинаре мы получим BEMJSON имеющихся страниц, напишем простые BEMHTML-шаблоны и посмотрим на некоторые интересные возможности BEMHTML.
Итак, немного про декларативные шаблоны.
Все привыкли к декларативной природе CSS, поэтому удобно провести аналогию.
Допустим, у нас есть список:
<ul class="menu">
<li class="menu__item">
Привет
<li>
<li class="menu__item">
BEM!
<li>
</ul>
Чтобы задать определенный внешний вид всем элементам списка можно написать CSS:
.menu__item {
background: red;
}
А если же хочется изменить связку ul
+ li
, например, на nav
+ a
? Что если это можно было бы сделать по аналогии с CSS, написав соответствующий «селектор» и просто задать другое значение свойству tag
?
Так это выглядит в BEMHTML:
block('menu')(
tag()('nav')
)
block('menu').elem('item')(
tag()('a')
)
Чтобы иметь возможность таким образом пребразовывать HTML необходима особая декларация страницы.
BEMJSON
BEMJSON — это описание структуры страницы в терминах БЭМ на JavaScript с зарезервированными полями. Указанный ранее список в BEMJSON описывается так:
({
block: 'menu',
tag: 'ul',
content: [
{
elem: 'item',
tag: 'li',
content: 'Привет'
},
{
elem: 'item',
tag: 'li',
content: 'BEM!'
}
]
})
BEMJSON компилирутся в HTML.
Избавиться от копипасты tag: 'li'
поможет BEMHTML-шаблон.
block('menu')(
tag()('ul')
)
block('menu').elem('item')(
tag()('li')
)
BEMHTML-шаблон накладывается на BEMJSON по аналогии с тем, как CSS накладывается на DOM-дерево. На выходе — получаем HTML.
BEMJSON для наших страниц
Код — 01858d
Если есть HTML, написанный по БЭМ, то BEMJSON можно получить автоматически с помощью пакета html2bemjson
npm install html2bemjson
Сборка
Код — eef725
Далее нужно дотюнить сборку:
- gulp научился собирать зависимости по BEMJSON, а не HTML
- добавился таск для компиляции HTML по BEMJSON с использованием BEMHTML-шаблонов
Вычисления во время компиляции в BEMJSON
Код — 51ec21
BEMJSON представляет собой plain JavaScript, поэтому позволяет любые вычисления во время компиляции — то, чего не достает HTML.
Например,
({
block: 'menu',
// построим BEMJSON списка динамически из массива текстов элементов
content: [
'Привет',
'BEM!'
].map(function(text) {
return {
elem: 'item',
content: text
};
})
})
({
block: 'menu',
// определим массив текстов динамически,
// который будет разным при каждой генерации итогового HTML
content: (function() {
return Math.random() > 0.5 ? ['Привет'] : ['Привет', 'BEM!'];
}()).map(function(text) {
return {
elem: 'item',
content: text
};
})
})
Напишем простые BEMHTML-шаблоны
Код — 17d9a6
Упростим полученный автоматической конвертацией BEMJSON:
- вынесем всю HTML-обвязку страницы в блок
page
- упростим представление меню в BEMJSON, сгенерировав BEMJSON самого списка элементов в шаблоне
- напишем простой шаблон для ссылки
Специальные возможности BEMHTML
Код — bad312
Шаблонизатор BEMHTML имеет некоторые интересные возможности:
Переопределение в зависимости от входных данных
Например, блок link
должен быть представлен в HTML span
-ом, а не ссылкой, если в BEMJSON не было поля url
.
Переопределение на уровне переопределения
Например, менюшка на странице с Поттером должна быть в HTML представлена тегом ol
, а на всех других страницах — ul
. Для этого достаточно определить блок меню на уровне potter.blocks
. После сборки всех шаблонов в один файл получим:
// common.blocks
block('menu')(...)
// potter.blocks
block('menu')(...)
По аналогии с CSS, последнее «правило» перебивает предыдущее.