...

суббота, 5 октября 2013 г.

[Из песочницы] jQuery.BEM — декларативный подход к работе с версткой по БЭМ методу

Уже много всего сказано про БЭМ, чем он хорош, чем плох, и повторяться сегодня мы не будем. Ниже рассказ про то, как работать с БЭМ DOM из jQuery в небольших проектах, где совесть и время не позволяют прикрутить bem-tools, bem-bl и bemhtml, а поработать с удобной системой верстки все-же хочется, оставив позади длинные селекторы в js файлах.

Заинтересованных приглашаю под кат, за подробностями и примерами использования.


Методология




БЭМ (аббр. Блок Элемент Модификатор) — особый способ организации HTML верстки, сильно облегчающий разработку и поддержку более-менее крупных сайтов и веб-приложений.

Полностью вводить вас в курс дела по методологии я не буду, в последнее время она становится очень популярной и материалов, откуда можно почерпнуть информацию предостаточно. Но если вышло так, что вы все еще не слышали о БЭМ и его преимуществах, рекомендую заглянуть:


Непосвященным вдвойне рекомендую посмотреть лекцию, во первых: не надо ничего читать, там видео, во вторых: объяснено все куда лучше первого варианта и мозги вправляет на ура.


Зачем еще одна реализация?




Не сказать что подобных штуковин так уж и много, единственный близкий аналог — фреймворк i-bem из библиотеки bem-bl, но заставить его работать вне родной среды обитания будет довольно проблематично.

Яндексовские bem-tools, bem-bl и вся возня со сборщиками и шаблонизаторами это, несомненно, круто. Но пока мы не доросли до проектов, имеющих пару сотен шаблонов, все это будет скорее мешать. Предположим, под рукой мы имеем маленький интернет-магазинчик, на каком-нибудь легеньком PHP-фреймворке. Здесь все это — стрельба из пушки по воробьям, однако рядом всегда будет любимый заказчик, которому все время приспичит что-нибудь поменять.


Методология уже хорошо зарекомендовала себя в удобстве масштабирования, а jQuery.BEM является лучшей возможностью работать с БЭМ версткой из JavaScript без применения толстых, сложных технологий. Все что нужно это jQuery, плагин jQuery.BEM и страничка сверстанная по БЭМ методу.


Я не утверждаю, что jQuery.BEM — самая лучшая реализация сего действа, она вполне себе может проигрывать в производительности тому-же i-bem из за сложных путешествий по DOM, но зато искоробочная и, на данный момент, самая удобная.


Работа с элементами




Предположим, у нас есть несколько блоков с товарами:

<div class="b-product">
<div class="b-product__name">Coffe</div>
<div class="b-product__price">$2</div>
</div>
<div class="b-product">
<div class="b-product__name">Tea</div>
<div class="b-product__price">$1</div>
</div>


Нам нужно произвести какое-либо действие с дочерними элементами первого блока:



$('.b-product').first().children('.b-product__name'); // jQuery
$('.b-product').first().elem('name'); // jQuery.BEM


С jQuery.BEM запись вышла короче. Разница в пару байт это, конечно, сомнительное приемущество, но в продакшене .elem() облегчает жизнь, если блок, например, нужно внезапно переименовать.


Работа с модификаторами




Добавляем модификатор


<div class="b-product">...</div>



$('.b-product').setMod('theme', 'premium'); // получим .b-product.b-prouct_theme_premium
$('.b-product').setMod('premium'); // получим .b-product.b-product_premium_yes


Удаляем модификатор


<div class="b-product b-prouct_theme_premium">...</div>



$('.b-product').delMod('theme', 'discount'); // несуществующий модификатор - ничего не изменится .b-product.b-prouct_theme_premium
$('.b-product').delMod('theme', 'premium'); // снесет класс .b-prouct_theme_premium
$('.b-product').delMod('theme'); // снесет модификатор theme с любым значением


Получаем модификатор


<div class="b-product b-prouct_theme_premium">...</div>



$('.b-product').getMod('theme'); // вернет "premium"
$('.b-product').getMod('discount'); // вернет null


Проверяем модификатор


<div class="b-product b-prouct_theme_premium">...</div>



$('.b-product').hasMod('theme'); // true
$('.b-product').hasMod('theme', 'premium'); // true
$('.b-product').hasMod('theme', 'discount'); // false


Фильтруем блоки по модификатору


<div class="b-product b-prouct_theme_premium">...</div>
<div class="b-product">...</div>



$('.b-product').byMod('theme', 'premium'); // вместо $('.b-product.b-prouct_theme_premium')
$('.b-product').byMod('theme'); // вместо $('.b-product.b-prouct_theme_premium')
$('.b-product').byNotMod('theme'); // вместо $('.b-product').not('.b-prouct_theme_premium')


Декларации блоков


Помимо системы именования классов, киллер-фичей БЭМ являются декларации. Они позволяют здорово облегчить работу с логикой блоков хотя-бы просто визуально отделяя их друг от друга.



bem.decl('b-product', {
onInit: function($this) {
// Добавляем элементу price модификатор size со значением large как только DOM будет готов
// $this внутри функии — обычный jQuery объект
$this.elem('price').setMod('size', 'large');
},
title: {
onMouseover: function($this) {
// Добавляем блоку b-product модификатор state со значением hover
$this.up().setMod('state', 'hover');

// Вызываем какую-нибудь вспомогательную функцию
this._customFunction();
},
_customFunction: function() {
console.log('I am helper function');
}
},
price: {
onSetmod: function($this, e, modKey, modVal) {
// Выводим в консоль информацию об установленном модификаторе элементу price
console.log('Modifer set:', modKey, modVal);
},
onDelmod($this, e, modKey, modVal) {
//
}
}
});


Можно декларировать только блоки или элементы с определенными модификаторами, а так же отдельные элементы блока:



bem.decl({ block: 'b-product', mod: 'theme:premium'}, {
//
});

bem.decl({ block: 'b-product', elem: 'price' }, {
//
});


Все события являются всплывающими и вешаются на document методом $(document).on(...), так что переопределять декларации, при изменении DOM на стороне клиента, не нужно.


Блоки могут общаться между собой событиями, функция начинающаяся с «on...», вешает на объект обработчик, так что в любом месте можно сделать $('.b-block').elem('title').trigger('on...');


Переопределение синтаксиса




По умолчанию, синтаксические параметры следуют оригинальному БЭМ. Если нужно избавиться от необходимости использования префиксов (b-, l-, g-, etc) или изменить разделитель блока и элемента с "__" на что-нибудь более удобное, используйте:

bem.setConfig({
namePrefix: '', // Префикс блока, можно регуляркой
elemPrefix: '-', // Префикс элемента
modPrefix: '_', // Префикс модификатора
modDlmtr: '-' // Разделитель модификатора и значения
});


Теперь имена классов в нашем HTML должны выглядеть немного по другому.



.block
.block-element
.block-element_modifer-value


В заключение




Плагин на условиях лицензии MIT доступен на GitHub. Буду рад, если он кому-нибудь облегчит жизнь и принесет пользу. Всегда рад аргументированной критике и вопросам.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Комментариев нет:

Отправить комментарий