Миграция
4.0.0
Изменения в блоке i-bem
Отдельный блок i-bem-dom
Элемент dom блока i-bem был перенесён в отдельный блок i-bem-dom.
Было:
modules.define('my-dom-block', ['i-bem__dom'], function(provide, BEMDOM) {
/* ... */
});
Стало:
modules.define('my-dom-block', ['i-bem-dom'], function(provide, bemDom) {
/* ... */
});
Блоки i-bem и i-bem-dom больше не являются классами, представляя собой модули с методами для декларации
БЭМ-сущностей, ссылками на классы БЭМ-сущностей и некоторыми дополнительными хелперами. Эти методы больше не являются методами класса для соответсвующих блоков.
Задача: #413.
Декларация
Декларация блока
Для декларации блока, вместо метода decl(), следует использовать метод declBlock().
Было:
modules.define('my-dom-block', ['i-bem__dom'], function(provide, BEMDOM) {
provide(BEMDOM.decl(this.name, { /* ... */ }));
});
Стало:
modules.define('my-dom-block', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declBlock(this.name, { /* ... */ }));
});
Декларация модификатора
Для декларации модификатора, вместо статического метода decl(), следует использовать статический метод declMod().
Было:
modules.define('my-dom-block', function(provide, MyDomBlock) {
provide(MyDomBlock.decl({ modName : 'my-mod', modVal : 'my-val' }, { /* ... */ }));
});
Стало:
modules.define('my-dom-block', function(provide, MyDomBlock) {
provide(MyDomBlock.declMod({ modName : 'my-mod', modVal : 'myVal' }, { /* ... */ }));
});
Декларация булевого модификатора
Было:
modules.define('my-dom-block', function(provide, MyDomBlock) {
provide(MyDomBlock.decl({ modName : 'my-mod', modVal : 'true' }, { /* ... */ }));
});
Стало:
modules.define('my-dom-block', function(provide, MyDomBlock) {
provide(MyDomBlock.declMod({ modName : 'my-mod' }, { /* ... */ }));
});
Задача: #1374.
Декларация для модификатора с любым значением
Было:
modules.define('my-dom-block', function(provide, MyDomBlock) {
provide(MyDomBlock.decl({ modName : 'my-mod' }, { /* ... */ }));
});
Стало:
modules.define('my-dom-block', function(provide, MyDomBlock) {
provide(MyDomBlock.declMod({ modName : 'my-mod', modVal : '*' }, { /* ... */ }));
});
Задача: #1376.
Доопределение блока
Вместо метода decl() класса блока следует использовать метод declBlock() модуля i-bem-dom.
Было:
modules.define('my-dom-block', function(provide, MyDomBlock) {
provide(MyDomBlock.decl({ /* ... */ }));
});
Стало:
modules.define('my-dom-block', ['i-bem-dom'], function(provide, bemDom, MyDomBlock) {
provide(bemDom.declBlock(MyDomBlock, { /* ... */ }));
});
Декларация наследуемого блока
Было:
modules.define('my-dom-block', ['i-bem__dom', 'my-base-dom-block'], function(provide, BEMDOM, MyBaseDomBlock) {
provide(BEMDOM.decl({ block : this.name, baseBlock : MyBaseDomBlock }, { /* ... */ }));
});
Стало:
modules.define('my-dom-block', ['i-bem-dom', 'my-base-dom-block'], function(provide, bemDom, MyBaseDomBlock) {
provide(bemDom.declBlock(this.name, MyBaseDomBlock, { /* ... */ }));
});
Декларация миксина
Метод declMix переименован в declMixin, чтобы отделить понятие
миксов нескольких БЭМ-сущностей на одном DOM-узле от миксинов на уровне JS.
Было:
modules.define('my-mix-block', ['i-bem__dom'], function(provide, BEMDOM) {
provide(BEMDOM.declMix(this.name, { /* ... */ }));
});
Стало:
modules.define('my-mixin-block', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declMixin({ /* ... */ }));
});
Примешивание миксина
Было:
modules.define('my-dom-block', ['i-bem__dom', 'my-mix-1', 'my-mix-2'], function(provide, BEMDOM) {
provide(BEMDOM.decl({ block : this.name, baseMix : ['my-mix-1', 'my-mix-2']}, { /* ... */ }));
});
Стало:
modules.define('my-dom-block', ['i-bem-dom', 'my-mixin-1', 'my-mixin-2'], function(provide, bemDom, MyMixin1, MyMixin2) {
provide(bemDom.declBlock(this.name, [MyMixin1, MyMixin2], { /* ... */ }));
});
Триггеры для изменения модификаторов
При декларации определённого модификатора (например, _my-mod_my-val) невозможно было задекларировать поведение
на удаление этого модификатора. Приходилось делать две декларации.
Было:
// my-dom-block_my-mod_my-val.js
modules.define('my-dom-block', function(provide, MyDomBlock) {
MyDomBlock.decl({
onSetMod : {
'my-mod' : {
'' : function() { /* ... */ } // декларация для удаления модификатора _my-mod_my-val
}
}
});
provide(MyDomBlock.decl({ modName : 'my-mod', modVal : 'my-val' }, { /* ... */ }));
});
Стало:
modules.define('my-dom-block', function(provide, MyDomBlock) {
provide(MyDomBlock.declMod({ modName : 'my-mod', modVal : 'my-val' }, {
onSetMod : {
'mod1' : {
'' : function() { /* ... */ } // декларация для удаления модификатора _my-mod_my-val
}
}
}));
});
Задача: #1025.
Появился сокращённый синтаксис для декларации поведения на изменение модификатора.
Было:
onSetMod : {
'my-mod' : {
'*' : function(modName, modVal, prevModVal) {
if(prevModVal === 'my-val') {
/* ... */ // декларация для изменения _my-mod_my-val в любое другое значение
}
}
}
}
Стало:
onSetMod : {
'my-mod' : {
'~my-val' : function() { /* ... */ } // декларация для изменения значения my-mod из my-val в любое другое значение
}
}
}
Было:
onSetMod : {
'my-mod' : {
'*' : function(modName, modVal) {
if(modVal !== 'my-val') {
/* ... */ // декларация для изменения my-mod в любое значение, кроме my-val
}
}
}
}
Стало:
onSetMod : {
'my-mod' : {
'!my-val' : function() { /* ... */ } // декларация для изменения my-mod в любое значение, кроме my-val
}
}
}
Задача: #1072.
Ленивая инициализация
Функциональность поля live была разделена на две части: поле lazyInit и метод onInit().
Было:
modules.define('my-dom-block', ['i-bem__dom'], function(provide, BEMDOM) {
provide(BEMDOM.decl(this.name, { /* ... */ }, {
live : true
}));
});
Стало:
modules.define('my-dom-block', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declBlock(this.name, { /* ... */ }, {
lazyInit : true
}));
});
Было:
modules.define('my-dom-block', ['i-bem__dom'], function(provide, BEMDOM) {
provide(BEMDOM.decl(this.name, { /* ... */ }, {
live : function() {
/* ... */
}
}));
});
Стало:
modules.define('my-dom-block', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declBlock(this.name, { /* ... */ }, {
lazyInit : true,
onInit : function() {
/* ... */
}
}));
});
Было:
modules.define('my-dom-block', ['i-bem__dom'], function(provide, BEMDOM) {
provide(BEMDOM.decl(this.name, { /* ... */ }, {
live : function() {
/* ... */
return false;
}
}));
});
Стало:
modules.define('my-dom-block', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declBlock(this.name, { /* ... */ }, {
onInit : function() {
/* ... */
}
}));
});
Было:
{
block : 'b1',
js : { live : false }
}
Стало:
{
block : 'b1',
js : { lazyInit : false }
}
Задача: #877.
Экземпляры для элементов
Удалены элемент elem-instances блока i-bem и модификатор elem-instances элемента dom блока i-bem.
Теперь соответствующая функциональность является частью i-bem и i-bem-dom.
Было:
modules.define('my-dom-block__my-elem', ['i-bem__dom'], function(provide, BEMDOM) {
provide(BEMDOM.decl({ block : 'my-dom-block', elem : 'my-elem' }, { /* ... */ }));
});
Стало:
modules.define('my-dom-block__my-elem', ['i-bem-dom'], function(provide, bemDom) {
provide(bemDom.declElem('my-dom-block', 'my-elem', { /* ... */ }));
});
Теперь метод _elem(elemName) экземпляра блока (бывший elem(elemName)) возвращает не jQuery-объект со всеми элементами
с именем elemName, а экземпляр класса элемента.
Для того, чтобы получить коллекцию экземпляров класса элемента, используйте метод _elems().
Не забудьте включить поддержку экземплятор для элементов в шаблонизаторе.
Опция elemJsInstances для bem-xjst или jsElem для BH.
Cпособы взаимодействия с элементами
Было:
this.setMod(this.elem('my-elem'), 'my-mod', 'my-val');
Стало:
this._elem('my-elem').setMod('my-mod', 'my-val');
Аналогично для методов getMod(), hasMod(), toggleMod(), delMod().
Удалённые методы и поля
Удалён метод dropElemCache(), теперь инвалидация кэшей осуществляется автоматически при модификациях DOM. Задача: #1352.
Из API блока удалены методы: elemify(), elemParams() и поле onElemSetMod. Соответствующая
им функциональность выражается через экземпляры элементов .
См. также изменения про методы поиска.
Задача: #581.
Методы поиска
Переименованы следующие методы:
findBlockInside()вfindChildBlock()findBlocksInside()вfindChildBlocks()findBlockOutside()вfindParentBlock()findBlocksOutside()вfindParentBlocks()findBlockOn()вfindMixedBlock()findBlocksOn()вfindMixedBlocks()
Из этих методов удален опциональный первый параметр про элемент.
Добавлены методы: findChildElem(), findChildElems(), findParentElem(), findParentElems(), findMixedElem(), findMixedElems().
Было:
this.findBlockInside(this.elem('my-elem'), 'my-block-2');
Стало:
this.findChildElem('my-elem').findChildBlock(MyBlock2);
Удалены методы: findElem(), closestElem(), вместо них следует использовать методы findChildElem()
и findParentElem(), соответсвенно.
Методы findChildBlocks(), findParentBlocks(), findMixedBlocks(), findChildElems(), findParentElems(),
findMixedElems() возвращают коллекции БЭМ-сущностей.
Методы findChildElem() и findChildElems() (в отличие от предыдущего аналога findElem) не выполняют поиск на собственных DOM-узлах экземпляра.
Было:
this.findElem('my-elem');
Стало:
this.findChildElems('my-elem').concat(this.findMixedElems('my-elem'));
Но рекомендуется обратить внимание, действительно ли необходимы оба поиска:
в большинстве случаев достаточно использовать или this.findChildElems('my-elem') или this.findMixedElems('my-elem').
Проверка вложенности
Вместо удаленного метода containsDomElem(), следует использовать метод containsEntity().
Было:
this.containsDomElem(someElem);
Стало:
this.containsEntity(someElem);
Коллекции
Функциональность элемента collection блока i-bem перестала быть опциональной.
Все методы возвращавшие массив БЭМ-сущностей, теперь возвращают коллекции.
Было:
this.findBlocksInside('my-block-2')[0].setMod('my-mod', 'my-val');
Стало:
this.findChildBlocks(MyBlock2).get(0).setMod('my-mod', 'my-val');
Было:
this.findBlocksInside('my-block-2').forEach(function(myBlock2) {
return myBlock2.setMod('my-mod', 'my-val');
});
Стало:
this.findChildBlocks(MyBlock2).setMod('my-mod', 'my-val');
Задача: #582.
События
API работы с событиями значильно упрощено. Удалены методы экземпляра блока: on(), un(), once(), bindTo(),
unbindFrom(), bindToDoc(), bindToWin(), unbindFromDoc(), unbindFromWin() и методы класса: liveBindTo(),
liveUnbindFrom(), on(), un(), once(), liveInitOnBlockEvent(), liveInitOnBlockInsideEvent().
Вместо них добавлены методы _domEvents() и _events(), возвращающие экземпляр класса менеджера событий, с методами
on(), un() и once();
DOM-события на экземплярах
Было:
BEMDOM.decl('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this.bindTo('click', this._onClick);
}
}
}
});
Стало:
bemDom.declBlock('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this._domEvents().on('click', this._onClick);
}
}
}
});
Было:
BEMDOM.decl('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this.bindToDoc('click', this._onDocClick);
}
}
}
});
Стало:
bemDom.declBlock('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this._domEvents(bemDom.doc).on('click', this._onDocClick);
}
}
}
});
Было:
BEMDOM.decl('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this.bindToWin('resize', this._onWinResize);
}
}
}
});
Стало:
bemDom.declBlock('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this._domEvents(bemDom.win).on('resize', this._onWinResize);
}
}
}
});
Ссылка на экземпляр
Если событие произошло на БЭМ-экземпляре, в объект события будет добавлено поле, ссылающееся на экземпляр:
this._domEvents('my-elem').on('click', function(e) {
e.bemTarget // ссылается на экземпляр `my-elem`
});
БЭМ-события на экземплярах
Было:
BEMDOM.decl('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this.findBlockOutside('my-block-2').on('my-event', this._onMyBlock2MyEvent, this);
},
'' : function() {
this.findBlockOutside('my-block-2').un('my-event', this._onMyBlock2MyEvent, this);
}
}
}
});
Стало:
bemDom.declBlock('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this._events(this.findParentBlock('my-block-2')).on('my-event', this._onMyBlock2MyEvent);
}
}
}
});
Следует обратить внимание, что теперь, отписка от событий происходит автоматически во время уничтожения экземпляра.
Делегированные DOM-события
Было:
BEMDOM.decl('my-block', { /* ... */ }, {
live : function() {
this.liveBindTo('click', this.prototype._onClick);
}
});
Стало:
bemDom.declBlock('my-block', { /* ... */ }, {
onInit : function() {
this._domEvents().on('click', this.prototype._onClick);
}
});
Было:
BEMDOM.decl('my-block', { /* ... */ }, {
live : function() {
this.liveBindTo('my-elem', 'click', this.prototype._onMyElemClick);
}
});
Стало:
bemDom.declBlock('my-block', { /* ... */ }, {
onInit : function() {
this._domEvents('my-elem').on('click', this.prototype._onMyElemClick);
}
});
Делегированные БЭМ-события
Было:
BEMDOM.decl('my-block', { /* ... */ }, {
live : function() {
this.liveInitOnBlockInsideEvent('my-event', 'my-block-2', this.prototype._onMyBlock2MyEvent);
}
});
Стало:
bemDom.declBlock('my-block', { /* ... */ }, {
onInit : function() {
this._events(MyBlock2).on('my-event', this.prototype._onMyBlock2MyEvent);
}
});
Следует обратить внимание, что параметр с функцией обработчиком события теперь обязательный.
Было:
modules.define('my-block', ['i-bem__dom', 'my-block-2'], function(provide, BEMDOM) {
provide(BEMDOM.decl(this.name, { /* ... */ }, {
live : function() {
this.liveInitOnBlockInsideEvent('my-event', 'my-block-2');
}
}));
});
Стало:
modules.define('my-block', ['i-bem-dom', 'my-block-2', 'functions'], function(provide, bemDom, MyBlock2, functions) {
provide(bemDom.declBlock(this.name, { /* ... */ }, {
onInit : function() {
this._events(MyBlock2).on('my-event', functions.noop);
}
}));
});
Было:
BEMDOM.decl('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
MyBlock2.on(this.domElem, 'my-event', this._onMyBlock2MyEvent, this);
},
'' : function() {
MyBlock2.un(this.domElem, 'my-event', this._onMyBlock2MyEvent, this);
}
}
}
});
Стало:
bemDom.declBlock('my-block', {
onSetMod : {
'js' : {
'inited' : function() {
this._events(MyBlock2).on('my-event', this._onMyBlock2MyEvent);
}
}
}
});
Следует обратить внимание, что теперь, отписка от событий происходит автоматически во время уничтожения экземпляра.
Взаимодействие стороннего кода с БЭМ-блоками
Получение экземпляра БЭМ-блока
Теперь, метод jQuery-объекта bem() принимает БЭМ-класс, вместо строки.
Было:
modules.require(['jquery', 'i-bem__dom'], function($, BEMDOM) {
var myBlock = $('.my-block').bem('my-block');
});
Стало:
modules.require(['jquery', 'my-block'], function($, MyBlock) {
var myBlock = $('.my-block').bem(MyBlock);
});
Подписка на БЭМ-события из стороннего кода
Было:
modules.require(['jquery', 'i-bem__dom'], function($, BEMDOM) {
$('.my-block').bem('my-block').on('my-event', function() { /* ... */ });
});
Стало:
modules.require(['jquery', 'my-block', 'events__observable'], function($, MyBlock, observable) {
observable($('.my-block').bem(MyBlock))
.on('my-event', function() { /* ... */ });
});
При этом в зависимости нужно добавить { block : 'events', elem : 'observable', mods : { type : 'bem-dom' } }.
Задача: #394.
Имена protected-методов начинаются с _
Переименованы protected-методы:
emit()в_emit()elem()в_elem()buildClass()в_buildClassName()buildSelector()в_buildSelector()getDefaultParams()в_getDefaultParams()
Удалённые методы
Удалён метод getMods().
Изменения в блоке querystring
Элемент querystring__uri стал блоком uri. Блок querystring стал элементом uri__querystring.
Задача: #967.
Изменения в блоке page
Элемент page__css больше не поддреживает поле ie. Используйте элемент page__conditional-comment.
Было:
{
block : 'page',
head : [
{ elem : 'css', url : 'my-css.css', ie : false },
{ elem : 'css', url : 'my-css', ie : true }
],
content : 'Page content'
}
Стало:
{
block : 'page',
head : [
{
elem : 'conditional-comment',
condition : '! IE',
content : { elem : 'css', url : 'my-css.css' }
},
{
elem : 'conditional-comment',
condition : '> IE 8',
content : { elem : 'css', url : 'my-css.ie.css' }
}
// и т.д. для других нужных версий IE
],
content : 'Page content'
}
Задача: #379.
3.0.0
Для миграции на версию 3.0.0 достаточно ознакомиться с историей изменений.
2.0.0
Для миграции на версию 2.0.0 достаточно ознакомиться с историей изменений.
1.0.0
Для версии 1.0.0 миграция подразумевается с использования bem-bl на использование bem-core.
Модули
Весь код теперь пишется в терминах модульной системы https://github.com/ymaps/modules. Все зависимости должны явно указываться в коде, обращения к глобальным объектам необходимо минимизировать, а, по возможности, и полностью исключить.
Пример:
modules.define(
'my-module', // имя модуля
['module-from-library', 'my-another-module'], // зависимости модуля
function(provide, moduleFromLibrary, myAnotherModule) { // декларация модуля, вызывается когда все зависимости "разрезолвлены"
// предоставление модуля
provide({
myModuleMethod : function() {}
});
});
TODO: дописать про изменение сборки (использование специальных технологий для js и как быть с кастомными сборщиками)
jQuery и jQuery-плагины
jQuery представлен модулем-оберткой jquery, который использует глобальный объект jQuery,
в случае если он уже присутствует на странице, в противном случае загружая его самостоятельно.
jQuery теперь используется только для операций, связанных непосредственно с DOM
(поиск элементов, подписка на события, установка/получение атрибутов элементов, и т.д.).
Для всех остальных операций написаны соответствующие модули, предоставляющие аналогичный функционал, но, при этом, не зависящие от jQuery:
модуль
objectsдля работы с объектами (с методамиextend,isEmpty,each)модуль
functionsдля работы с функциями (с методамиisFunctionиnoop)
Также, все jQuery-плагины, не связанные непосредственно с jQuery
($.observable, $.inherit, $.cookie, $.identify, $.throttle) стали модулями:
модуль
eventsвместо$.observableдля работы с событиями, предоставляющий "классы"EventsEmitterиEventмодуль
inheritвместо$.inheritдля работы с "классами" и наследованиеммодуль
cookieвместо$.cookieмодуль
identifyвместо$.identifyмодули
functions__throttle,functions__debounceвместо$.throttleи$.debounce, соответственно
Было:
// код блока
$.throttle()
// код блока
Стало:
module.define('my-module', ['functions__throttle'], function(provide, throttle) {
// код модуля
throttle()
// код модуля
});
BEM.DOM-блоки
Декларация
Вместо декларации через BEM.DOM.decl необходимо доопределять модуль i-bem__dom.
Было:
BEM.DOM.decl('block', /* ... */);
Стало:
modules.define('i-bem__dom', function(provide, BEMDOM) {
BEMDOM.decl('block', /* ... */);
provide(BEMDOM);
});
Конструктор
Необходимо использовать полную нотацию для обработчика установки модификатора js в значение inited.
Было:
onSetMod : {
js : function() {
// код конструктора
}
}
Стало:
onSetMod : {
'js' : {
'inited' : function() {
// код конструктора
}
}
}
Деструктор
Вместо метода destruct необходимо использовать обработчик установки модификатора js в пустое значение (удаление модификатора).
Вызывать __base для того, чтобы у блоков работал базовый деструктор, определенный в i-bem__dom, больше не нужно.
Было:
destruct : function() {
this.__base.apply(this, arguments);
// код деструктора
}
Стало:
onSetMod : {
js : {
'' : function() {
// код деструктора
}
}
}
Метод changeThis
Вместо метода changeThis необходимо использовать либо соответствующий параметр, либо нативный метод bind, если такой параметр отсутствует.
Было:
// код блока
obj.on('event', this.changeThis(this._method));
// код блока
Стало:
obj.on('event', this._method.bind(this));
// или лучше
obj.on('event', this._method, this);
Метод afterCurrentEvent
Вместо метода afterCurrentEvent необходимо использовать метод nextTick,
который гарантирует, что блок еще существует в момент исполнения callback'а
(если блок уже уничтожен к этому моменту, то callback не исполняется).
Было:
BEM.DOM.decl('block', {
method : function() {
this.afterCurrentEvent(function() {
/* ... */
});
}
});
Стало:
modules.define('i-bem__dom', function(provide, BEMDOM) {
BEMDOM.decl('block', {
method : function() {
this.nextTick(function() {
/* ... */
});
}
});
});
Метод findElem
Контекст для поиска элемента больше не задается строкой, вместо нее следует передавать jQuery-объект.
Было:
var nestedElem = this.findElem('parent-elem', 'nested-elem');
Стало:
var nestedElem = this.findElem(this.findElem('parent-elem'), 'nested-elem'),
oneMoreElem = this.findElem(this.elem('another-elem'), 'nested-elem');
Метод liveBindTo
Метод liveBindTo больше не поддерживает поле elemName для передачи имени элемента. Вместо него следует использовать поле elem.
Доступ до DOM-элемента в обработчике события
DOM-элемент, к которому был подвешен обработчик события теперь доступен
как $(e.currentTarget)вместо e.data.domElem.
Было:
onClick : function(e) {
e.data.domElem.attr(/* ... */);
}
Стало:
onClick : function(e) {
$(e.currentTarget).attr(/* ... */);
}
Каналы (channels)
Каналы больше не являются встроенными в BEM, теперь они являются самостоятельным модулем events__channels.
Было:
BEM.DOM.decl('block', {
method : function() {
BEM.channel('channel-name').on(/* ... */);
}
});
Стало:
modules.define('i-bem__dom', ['events__channels'], function(provide, channels, BEMDOM) {
BEMDOM.decl('block', {
method : function() {
channels('channel-name').on(/* ... */);
}
});
});
Блок i-system и канал sys событий tick, idle, wakeup
Этот блок и канал перестали существовать, вместо них появились отдельные модули: tick с событием tick и idle с событиями idle и wakeup.
Было:
BEM.DOM.decl('block', {
method : function() {
BEM.channel('sys').on('tick', /* ... */);
}
});
Стало:
modules.define('i-bem__dom', ['tick'], function(provide, tick, BEMDOM) {
BEMDOM.decl('block', {
method : function() {
tick.on('tick', /* ... */);
}
});
});
Было:
BEM.DOM.decl('block', {
method : function() {
BEM.channel('sys').on('wakeup', /* ... */);
}
});
Стало:
modules.define('i-bem__dom', ['idle'], function(provide, idle, BEMDOM) {
BEMDOM.decl('block', {
method : function() {
idle.on('wakeup', /* ... */);
}
});
});
BEM-блоки
Те BEM-блоки, которые использовались как хранилище для каких-то методов, при этом никак не использующие BEM-методологию, теперь могут быть написаны как модули.
Было:
BEM.decl('i-router', {
route : function() { /* ... */ }
});
Стало:
modules.define('router', function(provide) {
provide({
route : function() { /* ... */ }
});
});
Если же, по каким-то причинам, нужны именно BEM-блоки (не BEM.DOM-блоки), то их можно объявлять, доопределяя модуль i-bem.
Было:
BEM.decl('my-block', { /* ... */ });
Стало:
modules.define('i-bem', function(provide, BEM) {
BEM.decl('my-block', { /* ... */ });
provide(BEM);
});
Рефакторинг на примере блока b-spin
Было:
BEM.DOM.decl('b-spin', {
onSetMod : {
'js' : function() {
this._size = this.getMod('size') || /[\d]+/.exec(this.getMod('theme'))[0];
this._bgProp = 'background-position';
this._posPrefix = '0 -';
if (this.elem('icon').css('background-position-y')) { /* В IE нельзя получить свойство background-position, только background-position-y, поэтому костыляем */
this._bgProp = 'background-position-y';
this._posPrefix = '-';
}
this._curFrame = 0;
this.hasMod('progress') && this.channel('sys').on('tick', this._onTick, this);
},
'progress' : {
'yes' : function() {
this.channel('sys').on('tick', this._onTick, this);
},
'' : function() {
this.channel('sys').un('tick', this._onTick, this);
}
}
},
_onTick: function(){
var y = ++this._curFrame * this._size;
(y >= this._size * 36) && (this._curFrame = y = 0);
this.elem('icon').css(this._bgProp, this._posPrefix + y +'px');
},
destruct : function() {
this.channel('sys').un('tick', this._onTick, this);
this.__base.apply(this, arguments);
}
});
Стало:
modules.define(
'i-bem__dom',
['tick'],
function(provide, tick, BEMDOM) {
var FRAME_COUNT = 36;
BEMDOM.decl('b-spin', {
onSetMod : {
'js' : {
'inited' : function() { // конструктор
var hasBackgroundPositionY = !!this.elem('icon').css('background-position-y')); /* В IE нельзя получить свойство background-position, только background-position-y */
this._bgProp = hasBackgroundPositionY? 'background-position-y' : 'background-position';
this._posPrefix = hasBackgroundPositionY? '-' : '0 -';
this._curFrame = 0;
this._size = Number(this.getMod('size') || /[\d]+/.exec(this.getMod('theme'))[0]);
this.hasMod('progress') && this._bindToTick();
},
'' : function() { // деструктор
this._unbindFromTick();
}
},
'progress' : {
'true' : function() {
this._bindToTick();
},
'' : function() {
this._unbindFromTick();
}
}
},
_bindToTick : function() {
tick.on('tick', this._onTick, this);
},
_unbindFromTick : function() {
tick.un('tick', this._onTick, this);
},
_onTick : function() {
var offset;
this._curFrame++ >= FRAME_COUNT?
offset = this._curFrame * this._size :
this._curFrame = offset = 0;
this.elem('icon').css(this._bgProp, this._posPrefix + offset + 'px');
}
});
provide(BEMDOM);
});