Форум

Методология

Инструментарий

Платформа

Сообщество

Привязка 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-представления необходимо позаботиться о сохранении ссылки на этот экземпляр для блоков, которым нужно с ним взаимодействовать.

Если вы заметили ошибку или хотите чем-то дополнить статью, вы всегда можете или написать нам об этом на Гитхабе, или поправить статью с помощью prose.io.