Инициализация
Инициализация — это создание в памяти браузера JS-объекта, соответствующего экземпляру блока или элемента. Инициализация экземпляров блоков или элементов выполняется функцией init([ctx])
из модуля i-bem-dom
на заданном фрагменте DOM-дерева ctx
.
Каждому экземпляру можно приписать три состояния:
не инициализирован — JS-объект не создан
инициализирован — JS-объект создан в памяти браузера
уничтожен — удалены все ссылки на JS-объект экземпляра, и он может быть удален сборщиком мусора.
В i-bem.js
эти состояния описываются с помощью служебного модификатора js
.
До инициализации экземпляр не имеет модификатора
js
.
<div class="my-block i-bem" data-bem='{ "my-block" : {} }'>...</div>
В момент инициализации экземпляру устанавливается модификатор
js
в значенииinited
.
<div class="my-block i-bem my-block_js_inited" data-bem='{ "my-block" : {} }'>...</div>
Если в процессе работы удаляется фрагмент DOM-дерева (при помощи метода
destruct()
модуляi-bem-dom
), то вместе с ним удаляются экземпляры, все HTML-элементы которых находятся в этом фрагменте. Перед удалением экземпляра модификаторjs
удаляется, чтобы выполнились деструкторы экземпляра.
Примечание Если экземпляр блока или элемента был привязан к нескольким HTML-элементам, экземпляр будет существовать, пока в HTML-дереве сохраняется хотя бы один HTML-элемент, с которым он связан.
Если на HTML-элементе размещено несколько экземпляров других блоков или элементов, то инициализация одного из них (появление модификатора js
со значением inited
) не влияет на инициализацию остальных.
Пример
На HTML-элементе инициализирован только экземпляр блока my-block
. Экземпляр блока lazy-block
не инициализирован:
<div class="my-block my-block_js_inited lazy-block i-bem" data-bem='{ "my-block" : {}, "lazy-block" : {} }'>
...
</div>
Примечание Наличие модификатора
js
позволяет писать разные CSS-стили для блока или элемента в зависимости от того, инициализирован он или нет.
Конструктор экземпляра блока и элемента
На изменение значений модификатора js
можно назначать триггеры так же, как и для любых других модификаторов.
Триггер на установку модификатора js
в значение inited
выполняется при инициализации экземпляра.
Этот триггер можно считать конструктором:
bemDom.declBlock('my-block', {
onSetMod : {
'js' : {
'inited' : function() { /* ... */ } // конструктор экземпляра
}
}
});
Деструктор экземпляра блока и элемента
Моментом удаления экземпляра является момент уничтожения всех ссылок на его JS-объект, после чего он может быть удален из памяти браузера сборщиком мусора.
Триггер на удаление модификатора js
(установку в пустое значение ''
) выполняется перед удалением блока. Такой триггер можно считать деструктором.
bemDom.declBlock('my-block', {
onSetMod : {
'js' : {
'' : function() { /* ... */ } // деструктор экземпляра
}
}
});
Волны инициализации
Инициализация экземпляров блоков и элементов, присутствующих на странице, не обязательно происходит одновременно. Они могут динамически добавляться в ходе работы, инициализироваться по запросу или событию. Инициализация очередной группы блоков или элементов называется волной инициализации.
Новая волна инициализации создается в следующих случаях:
Автоматическая инициализация блоков и элементов по событию
domReady
.Явный вызов инициализации на указанном фрагменте DOM-дерева.
Автоматическая инициализация
i-bem.js
позволяет автоматически инициализировать блоки и элементы с DOM-представлением в момент наступления DOM-события domReady
.
Включить автоматическую инициализацию можно, указав блок i-bem
с модификатором init
в значении auto
в файле зависимостей .deps.js
.
Пример файла .deps.js
:
({
shouldDeps : [
{
block : 'i-bem',
elem : 'dom',
mods : { init : 'auto' }
}
]
})
Блок page уже содержит в зависимостях i-bem-dom_init_auto
, поэтому если он используется в проекте, не требуется ничего дополнительно подключать.
Примечание Блоки и элементы, для которых задекларирована ленивая инициализация, не будут инициализированы автоматически.
Ленивая инициализация
Если на странице размещено много экземпляров блоков и элементов, их автоматическая инициализация в момент загрузки страницы нежелательна, так как она увеличивает время загрузки и объем памяти, затрачиваемой браузером.
Рекомендуется инициализировать блоки и элементы только в тот момент, когда их функциональность потребуется пользователю, например, по клику на блок. Такая инициализация называется ленивой.
Для декларации ленивой инициализации, в декларации зарезервировано статическое свойство lazyInit
типа Boolean
.
При lazyInit : true
, блоки или элемнеты данного класса будут инициализированы только при попытке получить соответствующий экземпляр (см. раздел «Взаимодействие блоков»).
modules.define('my-block', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declBlock(this.name, {
onSetMod : {
'js' : {
'inited' : function() {
// этот код будет выполняться при первом обращении к экземпляру блока
}
}
}
}, {
lazyInit : true
}));
});
Декларация с lazyInit : false
позволяет отменить ленивую инициализацию, заданную на другом уровне переопределения.
Примечание Ленивая инициализация может быть отменена для конкретного экземпляра. Для этого нужно указать в параметрах HTML-элемента, к которому привязан экземпляр
data-bem='{ "my-block" : { "lazyInit" : false } }'
.
Инициализация класса
В терминах i-bem-dom
существует понятие инициализация класса. Она происходит в момент прохождения волны инициализации на HTML-фрагменте, когда в нем впервые за время жизни приложения встречается блок или элемент данного класса.
Инициализация класса необходима для реализации ленивой инициализации по DOM- или БЭМ-событию. Для этого в декларации зарезервирован статический метод onInit
, внутри которого можно подписаться на нужные события.
Пример
Блок button
будет инициализирован по DOM-событию click
на DOM-узле блока.
modules.define('button', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declBlock(this.name, {
onSetMod : {
'js' : {
'inited' : function() {
// выполняется при первом DOM-событии "click"
}
}
},
_onClick: function(e) {
// выполняется при каждом DOM-событии "click"
}
}, {
lazyInit : true,
onInit : function() {
this._domEvents().on(
'click',
this.prototype._onClick); // в момент клика будет создан экземпляр блока и вызван его метод _onClick
}
}));
});
Блок my-form
инициализируется по БЭМ-событию click
вложенного в него блока button
.
modules.define('my-form', ['i-bem-dom', 'button'], function(provide, bemDom, Button) {
provide(bemDom.declBlock(this.name, {
_onButtonClick : function(e, data) {
// функция-обработчик БЭМ-события click на вложенных блоках button
}
}, {
lazyInit : true,
onInit : function() {
this._events(Button).on('click', this.prototype._onButtonClick);
}
}));
});
Примечание Свойства
lazyInit
иonInit
относятся к статическим свойствам класса. Поэтому даже если оно задано в декларации блока или элемента с определенным модификатором, они будут применены ко всем экземплярам данного класса, вне зависимости от модификаторов.
Инициализация блоков и элементов на фрагменте DOM-дерева
Процедура инициализации JS-объектов может быть вызвана явно для указанного фрагмента DOM-дерева. Такая необходимость возникает при динамическом обновлении блоков или элементов.
Следующие функции выполняют динамическую инициализацию блоков и элементов:
init()
,destruct()
– инициализация и уничтожение экземпляров на указанном фрагменте DOM-дерева.update()
,replace()
,append()
,prepend()
,before()
,after()
– обновление фрагмента DOM-дерева с одновременной инициализацией на обновленном фрагменте.
Пример использования функций, выполняющих динамическую инициализацию см. в разделе «Динамическое обновление блоков и элементов в DOM-дереве».
Инициализация и удаление блоков без DOM-представления
Для создания JS-объектов блока или элемента без DOM-представления (не привязанного к HTML-элементу) служит статический метод create()
классов Block
или Elem
из модуля i-bem
.
Метод принимает аргументы:
mods
{Object}
– модификаторы создаваемого блока или элемента.params
{Object}
– параметры блока или элемента.
Возвращает экземпляр указанного класса.
Удаление экземпляров блоков и элементов без DOM-представления не может быть выполнено автоматически. Блоки и элементы без DOM-представления представляют собой обычные JS-объекты и удаляются в момент удаления всех ссылок на объект.