Привязка JS-блоков к HTML
JavaScript-компоненты в i-bem.js
служат для «оживления» HTML-элементов страницы. Типовая задача JS-блока — установка реакции на события внутри HTML-фрагмента.
В i-bem.js
первичным «каркасом» является HTML-дерево документа. В нем размечаются точки, к которым привязаны интерактивные элементы интерфейса — JS-блоки. Точка привязки JS-блока — HTML-элемент (DOM-узел), в атрибуте class
которого указано имя блока, а в атрибуте data-bem
— параметры блока.
При загрузке страницы в браузере выполняется инициализация блоков. В ходе нее создаются экземпляры блоков — JS-объекты всех блоков, упомянутых в классах HTML-элементов страницы. JS-объект, привязанный к HTML-элементу, обрабатывает происходящие на нем DOM-события и хранит состояния данного экземпляра блока.
Такой способ привязки JavaScript-компонентов к HTML имеет следующие преимущества:
естественная деградация интерфейса на клиентах с отключенным JavaScript;
прогрессивный рендеринг — возможность начинать отрисовку элементов интерфейса до окончания загрузки всех данных страницы (например, изображений).
Примечание Начиная с версии
bem-core@v4.0.0
всё описанное ниже для блоков так же справедливо для элементов.
Механизм привязки блоков
Чтобы привязать блок к HTML-элементу (например, <div>...</div>
), необходимо:
Декларировать блок в
i-bem
.
Cоздать модуль ym, содержащий JS-реализацию блока (декларацию). Для этого строка с именем блока передается первым аргументом методам modules.define
и bemDom.declBlock
.
modules.define('my-block', ['i-bem-dom'], function(provide, bemDom){
provide(bemDom.declBlock(this.name,
{
/* методы экземпляра */
},
{
/* статические методы */
}
));
});
На уровне проекта каждый модуль ym
обычно хранится как отдельный файл технологии js
. Например, декларация my-block
в проекте может храниться как my-block/my-block.js
– файл my-block.js
, вложенный в папку my-block
.
Отметить блок в HTML-дереве.
Добавить HTML-элементу атрибут
class
с именем блока.<div class="my-block">...</div>
Разрешить инициализацию экземпляра блока.
Включить класс
i-bem
в список классов HTML-элемента. Наличие этого класса укажет фреймворку, что HTML-элемент связан с JS-блоком.<div class="my-block i-bem">...</div>
Передать параметры экземпляру блока.
Поместить параметры блока в атрибут
data-bem
. Параметры блока записываются в формате JSON и представляют собой хеш вида:имя блока : хэш параметров
. Параметры будут переданы экземпляру блока в момент инициализации.<div class="my-block i-bem" data-bem='{ "my-block": { "name": "ya" } }'>...</div>
Связь блоков с HTML-элементами
Одному HTML-элементу не обязательно должен соответствовать один экземпляр блока. Возможны следующие типы связи между блоками и HTML-элементами:
Один HTML-элемент — один JS-блок
Самый простой и распространенный способ привязки блоков к HTML.
Пример
HTML-элемент div
, на котором размещен блок my-block
. Параметры блока: пустой список {}
.
<div class="my-block i-bem" data-bem='{ "my-block": {} }'>
...
</div>
Один HTML-элемент — несколько JS-блоков
Техника размещения нескольких блоков на одном HTML-элементе в БЭМ-методологии называется микс.
Пример
HTML-элемент div
, на котором размещены:
блок
user
с параметромname
:pushkin
;блок
avatar
с параметромimg
:http://...
.
<div class="user avatar i-bem"
data-bem='{
"user": { "name": "pushkin" },
"avatar": { "img": "http://..." }
}'>
...
</div>
Один JS-блок на нескольких HTML-элементах
Такой дизайн удобен, если нужно согласовать состояния нескольких компонентов блока.
Чтобы привязать экземпляр блока к нескольким HTML-элементам, нужно указать им в атрибуте data-bem
одинаковое значение параметра id
. Значением id
может быть произвольная строка.
Пример
Экземпляр блока notebook
привязан к HTML-элементам div
и span
. В параметрах блока указан общий id
— maintab
.
<div class="notebook i-bem" data-bem='{ "notebook": { "id": "maintab" }}'>
</div>
...
<span class="notebook i-bem" data-bem='{ "notebook": { "id": "maintab" }}'>
</span>
В результате при инициализации блоков создается один JS-объект, поле domElem которого содержит ссылки на jQuery-объекты обоих DOM-узлов.
Например, виджет «вкладка», где клик по заголовку вкладки (первый HTML-элемент), меняет ее содержимое (второй HTML-элемент).
Другой пример: маркер, обозначающий точку на карте (первый элемент), и связанное с ним описание точки в списке рядом (второй элемент).
Идентификатор id
используется только в момент инициализации экземпляра блока. Значение id
должно быть уникальным для экземпляров одного блока в рамках одной волны инициализации.
Блоки без DOM-представления
Инфраструктурный код, решающий общие задачи интерфейса (связь с бэкэндом, вспомогательные методы), можно оформить в виде блока. Это позволит выражать состояния блока с помощью модификаторов, на изменение которых смогут подписаться другие блоки.
Чтобы не привязывать такие блоки к HTML-дереву искусственно в i-bem.js
можно создавать блоки без DOM-представления.
Блоки без DOM-представления:
не требуют привязки к HTML-коду страницы;
должны быть явно инициализированы и уничтожены.
Доступ к экземплярам блоков без DOM-представления
При создании экземпляра блока без DOM-представления необходимо позаботиться о сохранении ссылки на этот экземпляр для блоков, которым нужно с ним взаимодействовать.