Пытаюсь перевести проект на полный бем-стек. Пытаюсь сделать блок выбора параметров товара ( например, размера ).
Есть блок .params
, внутри него лежат элементы ( собственно размеры ) .params__item
.
Делаю ленивую инициализацию по клику на эелемент .params__item
.
При клике хочу назначить элементу на котором кликнули модификатор _selected
.
Пытаюсь это сделать через this.setMod(this.elem('item'), 'selected')
но в таком случае модификатор устанавливается всем элементам. Как их фильтровать?
Как вообще работать с домом внутри блока? Допустимо ли извлекать данные из event, например event.target? Где граница ипосльзования фрейморка и работа с чистым js?
Можно воспользоваться тем фактом, что
this.domElem
возвращает ссылку на jQuery-chain с DOM-элементами данного блока. Аналогично работаетthis.elem('имя-элемента')
.Да, конечно. Насколько я понимаю, этот ответ автоматически отвечает и на вопрос про поиск кликнутого элемента?
i-bem.js
предоставляет хелперы для работы именно с предметной областью БЭМ: отреагировать на изменение модификатора, найти элемент или другой блок, проинициализировать новые блоки после динамической вставки и прочие действия, связанные со словами «блок», «элемент» и «модификатор».Для всего остального предоставляются ссылки на DOM-узлы, завернутые в jQuery-коллекции.
@tadatuta Правильно ли я понимаю, что все остальное мы пишем как обычный JS код?
Например, когда я выделил элемент ( конкретный параметр, в моем случае ), я присваиваю ему модификатор хелперами i-bem, дальше ставлю реакцию на изменения модификатора и дальше описываю его логику не обращая внимание на i-bem? ( послать аякс-запрос, навесить DOM-событие и так далее ).
И, в таком случае, раз логика выбора размера товара инкапсулирована в блоке
.params
, а мне нужно после выбора размера активировать кнопку "Купить", которая выведена как.button .buy-block__buy-button
, то есть, является совсем сторонней БЭМ-сущностью - я должен заиженктить ее в блок.params
и работать с ней?2) BEM-события это и есть установка модификаторов и их изменения? Пытаюсь понять отличие BEM-событий от DOM-событий. 3) Как у вас в Яндексе принято реализовывать события через pub/sub ? Отдельный блок без представления? Я имею ввиду нечто вроде
$(window).trigger('some-action') - $(window).on('some-action', doSomethingWithNode)
Послать AJAX-запрос — да, вставить ответ от запроса в DOM — нет (нужно вызвать инициализацию на новых узлах, поэтому удобно использовать хелперы BEMDOM.{append,prepend,replace,update} (полностью аналогично одноименным методам из jQuery, но вызывает инит).
Навесить DOM-событие — тоже через хелперы
i-bem.js
(this.bindTo()
), это позволит автоматически отписаться при удалении блока.Вот полный список методов
i-bem.js
: https://ru.bem.info/libs/bem-core/current/desktop/i-bem/jsdoc/ Все остальное следует решать напрямую.Есть несколько способов (привожу в порядке субъективного предпочтения):
params
. БЭМ-события всплывают аналогично DOM-событиям, поэтому возможно подписаться наclick
по кнопке, ограничив контекст элементом родительского блока:this.on(this.elem('buy'), 'click', this._onClick)
.params
. Тогда из кодаparams
можно будет найти свой элемент и уже на нем кнопку:this.findBlockInside('buy', 'button');
// найти блокbutton
на своем элементеbuy
.params
.Изменение модификатора порождает БЭМ-события, но они на этом не ограничиваются. В общем случае БЭМ-события — это абстракция, которая позволяет написать кастомной логики поверх DOM-событий. Например, если у кнопки выставлен модификатор
_disabled
, DOM-клики на ней по-прежнему будут триггериться, а при генерации BEM-событий можно эту логику учесть. Либо можно триггеритьclick
не только собственно на клик, но и нажатие спейса на клавиатуре. И т.д.Есть вот такая специальная сущность: https://ru.bem.info/libs/bem-core/current/desktop/events/#Элемент-channels-блока-events
@tadatuta
Очень полезные ответы. Спасибо! По вопросу о кнопке, которая должна реагировать на клик попараметру - подходит только 3й вариант, поскольку у них нет связей родитель-ребенок и они находятся в разных местах. Или при миксе такая связь не обязательна? Можно краткий пример, когда кнопка и блок параметров это абсолютно разные блоки? Так как в моей понимании при миксе
.prarms__buy-button
кнопка должна находится внутри блока.params
В общем случае один блок может быть расположен на разных DOM-узлах (см. https://ru.bem.info/platform/i-bem/html-binding/#Один-js-блок-на-нескольких-html-элементах), но да, это не самый очевидный вариант.
Возможно в данном случае стоит решать задачу через общего родителя у
params
и кнопки? Он смог бы подписаться на нажатие на кнопку, найти блокparams
внутри себя с помощьюfindBlockInside()
и вызвать на нем нужный метод.@tadatuta
Обший родитель скорее обычный блок лэяута. Он вряд ли должен знать о существовании каких-то
.params
и.buy-button
. Наверное, нужно делать глобальный pub/sub и подписывать блок кнопки на событие типаonParamsChange
Я не знаю, как выглядит/работает проект, так что конкретное решение посоветовать не могу. Но интуитивно кажется странным, что кнопка находится где-то далеко от того блока, на который воздействует и что она и
params
не находятся внутри какой-нибудь общей формы.Как вариант, можно примиксовать осмысленного родителя к текущему родителю-лейауту.
Впрочем, вариант с pub/sub тоже вполне рабочий.