Работа с DOM-деревом
DOM-узел экземпляра блока и элемента
В контексте экземпляра блока и элемента с DOM-представлением зарезервировано поле this.domElem, содержащее jQuery-объект со ссылками на все DOM-узлы, с которыми связан данный экземпляр.
Поиск экземпляров блоков и элементов в DOM-дереве
Обращение к другому блоку в i-bem.js выполняется из текущего блока, размещенного на определенном узле DOM-дерева. Поиск других блоков в DOM-дереве может вестись по трём направлениям (осям) относительно DOM-узла текущего блока:
Внутри блока — на DOM-узлах, вложенных в DOM-узел текущего блока.
Вспомогательные методы:
findChildBlock(block);findChildBlocks(block);findChildElem(elem);findChildElems(elem).
Снаружи блока — на DOM-узлах, потомком которых является DOM-узел текущего блока.
Вспомогательные методы:
findParentBlock(block);findParentBlocks(block);findParentElem(elem);findParentElems(elem).
На себе — на том же DOM-узле, на котором размещен текущий блок. Это актуально в случае размещения нескольких JS-блоков на одном DOM-узле (микс).
Вспомогательные методы:
findMixedBlock(block);findMixedBlocks(block);findMixedElem(elem);findMixedElems(elem).
Методы
findMixedBlocks(block)иfindMixedElems(elem)могут возвращать больше одного экземпляра в случае, когда к блоку или элементу с несколькими DOM-узлами примешаны несколько разных экземпляров одного и того же блока (block) или (elem).
Сигнатура вспомогательных методов поиска блоков идентична:
block{Function|Object}– класс или описание искомого блока. Описанием служит хеш вида{ block : MyBlock, modName : 'my-mod', modVal : 'my-val' }.
Для методов поиска элементов:
elem{String|Function|Object}– имя, класс или описание искомого элемента. Описанием служит хеш вида{ elem : MyElem, modName : 'my-mod', modVal : 'my-val' }или{ elem : 'my-elem', modName : 'my-mod', modVal : 'my-val' };[strictMode=false]{Boolean}– нужно ли учитывать вложенность одноимённых блоков.
Вспомогательные методы для поиска парные. Различаются возвращаемым значением:
find<Direction>Blockиfind<Direction>Elem– возвращает первый найденный экземплярfind<Direction>Blocksfind<Direction>Elems– возвращает коллекцию найденных экземпляров
Пример
modules.define('attach', ['i-bem-dom', 'button'], function(provide, bemDom, Button) {
provide(bemDom.declBlock(this.name, {
onSetMod: {
'js': {
'inited' : function(modName, modVal) {
this._button = this.findChildBlock(Button);
}
}
}
}));
});
Примечание Не используйте jQuery-селекторы для поиска блоков и элементов.
i-bem.jsпредоставляет высокоуровневое API для доступа к DOM-узлам блоков и элементов. Прямое обращение к DOM-дереву делает код менее устойчивым к изменениям БЭМ-библиотек и может привести к возникновению сложно обнаруживаемых ошибок.
Кэширующие методы поиска экземпляров элементов
Для оптимизации производительности для распространённых случаев поиска элементов одновременно по двум осям (внутри и на себе), служат кэширующие методы _elem(elem) и _elems(elem). Оба метода принимают один параметр:
elem{String|Function|Object}– имя, класс или описание искомого элемента. Описанием служит хеш вида{ elem : MyElem, modName : 'my-mod', modVal : 'my-val' }или{ elem : 'my-elem', modName : 'my-mod', modVal : 'my-val' }.
Аналогично с некэширующими методами поиска кеширующие методы различаются возвращаемым значением:
_elem()– возвращает первый найденный экземпляр элемента_elems()– возвращает коллекцию найденных экземпляров элементов
Пример
modules.define('button', ['i-bem-dom', 'button__control'], function(provide, bemDom, ButtonControl) {
provide(bemDom.declBlock(this.name, {
setName : function(name) {
this._elem(ButtonControl).setName(name);
},
setValue : function(value) {
this._elem(ButtonControl).setValue(value);
}
}));
});
Примечание Результат кеширующих методов нет необходимости сохранять в переменную (см. предыдущий пример). В то время как для некеширующих методов хорошей практикой является единоразовый поиск всего, что нужно, с сохранением в переменную или внутреннее поле.
Примечание В случае использования элементов без JS реализации и динамического обновления DOM-дерева может понадобиться метод инвалидации кеша элементов
_dropElemCache('elements'). Он принимает опциональный параметр с одним или несколькими именами элементов через пробел.
Кеширующий метод поиска экземпляра блока элемента
_block()— возвращает экземпляр блока для элемента.
Пример
modules.define('my-form__submit-control', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declElem('my-form', 'submit-control', {
_onClick : function() {
this._block().submit();
}
}));
});
Проверка вложенности
containsEntity(entity)— проверяет вложен ли переданный экземплярentity{i-bem-dom:Entity}в текущий экземпляр.
Динамическое обновление блоков и элементов в DOM-дереве
В модуле i-bem-dom предусмотрены следующие функции для добавления и замены фрагментов DOM-дерева.
Удалить DOM-фрагмент:
destruct(ctx, [excludeSelf])
Сигнатура функции:
ctx{jQuery}– корневой DOM-элемент. Удаляется со всем вложенными DOM-узлами.[excludeSelf]{Boolean}– не удалять корневой DOM-элемент, если значениеtrue. По умолчаниюfalse.
Добавить DOM-фрагмент:
append(ctx, content)— в конец указанного контекста;prepend(ctx, content)— в начало указанного контекста;before(ctx, content)— перед указанным контекстом;after(ctx, content)— после указанного контекста;
Заместить DOM-фрагмент:
update(ctx, content)— внутри указанного контекста;replace(ctx, content)— заменить указанный контекст новым DOM-фрагментом.
Сигнатура функций добавления и замены идентична:
ctx{jQuery}– DOM-элементcontent{jQuery|String}– содержимое
Все функции возвращают DOM-элемент с содержимым для которого была выполнена инициализация для новых блоков и элементов.
Чтобы упростить создание БЭМ-сущностей на обновляемых фрагментах DOM-дерева, можно использовать шаблонизатор BEMHTML, подключив его в качестве ym-модуля. БЭМ-сущности описываются в формате BEMJSON непосредственно в коде блока. Функция BEMHTML.apply генерирует HTML-элементы по BEMJSON-декларации в соответствии с правилами именования БЭМ.
Пример
Метод _updateFileElem блока attach удаляет элемент file, если он существовал, и создает новый элемент с помощью функции BEMHTML.apply:
modules.define( 'attach', ['BEMHTML', 'i-bem-dom'], function(provide, BEMHTML, bemDom) {
provide(bemDom.declBlock(this.name, {
_updateFileElem : function() {
bemDom.replace(
this._elem('file').domElem,
BEMHTML.apply({
block : 'attach',
elem : 'file',
content : this.getValue()
}));
return this;
}
}));
});