Пытаюсь перевести проект на полный бем-стек. Пытаюсь сделать блок выбора параметров товара ( например, размера ).
Есть блок .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 тоже вполне рабочий.