Начал перетаскивать проект на новые версии bem-components, bem-core. После банальных переименований методов упёрся в непонятное:
Что использовать вместо:
elem = block.elemify(domNode, 'elem')
(найдено; но, блин... знаете...)block = domNode.bem('block')
(Также предстоит ещё разбираться с кучей мест, где используется старый menu-item
вместо menu__item
. Наверное, что-то ещё вылезет; приду сюда плакать обратно.)
Для элементов теперь создаются полноценные i-bem-классы, так что для них справедливо все то же, что и для блоков, т.е.
Вот здесь https://github.com/bem/bem-components/commit/a8002944624c9b37c05eff7de4ee33510fb19e1e можно найти изменения, переводящие bem-components на новый bem-core, думаю, там затронуто большинство нововведений. С остальными проблемами миграции обязательно поможем.
Да, спасибо. Полезно. Ещё вот это помогает: bem-core/4.2.0/migration.
Хотя, конечно, много странного. Для поиска блоков по строке пришлось свой хелпер строить (генерим хеш с вложенными методами
getEntityName
); надеюсь, что эти изменения действительно полезны и необходимы и мой секс не напрасен. %))Последнее, во что упёрся, -- это отсутствие
block.getMods()
. Оно вообще выпилено или есть дублирующие методы? Пока не могу найти. Первое, что вижу, это дёргать значения из_modCache
, но что-то мне подсказывает, что так поступать не стоит. Есть способы?ух, сильно подозреваю, что все перечисленные костыли просто не нужны, если правильно готовить.
getMods
выпилили сознательно, т.к. это изначально несколько странный API был.Про причины изменений можно послушать @veged, например, тут: https://events.yandex.ru/lib/talks/3685/
По нашему опыту на двух достаточно больших проектах с новым bem-core приходится чуть больше писать, но код становится сильно прямее.
Ну, нет, я целиком и полностью доверяю разработчикам. Именно поэтому в основном на себя и ругаюсь.
В общем, пытался честно жить с поиском по дескрипторам блоков, но получалось очень уж заморочно: (а) почти сразу словил циклические зависимости и (б) в части случаев неизвестно заранее, какие блоки надо будет искать: зависит от предоставляемого блоку набора данных, откуда выбираются нужные параметры. Понятно, что, имея в виду подобное развитие идеологии, можно было бы как-то перепроектировать схему работы с данными, но сейчас перелопачивать всё совершенно не с руки.
Кроме того, совершенно не понял, как в рамках этой схемы искать внутри блока экземпляры своего же собственного класса: откуда в этом случае брать дескриптор, если блок создаётся "с чистого листа" и этот самый дескриптор отсуствует? Должен же быть какой-то способ?
Ещё раз прошу помощи в практическом вопросе -- до сих пор не понял, как правильно заменить обращение к
getMods
. Ситуация в общем случае примерно такова: в динамике (на клиенте) создаются элементы, шаблоны которых зависят от установленных модификаторов блока. В старом коде делал что-то вроде:Сейчас вижу несколько способов, ни один из которых не кажется оптимальным: (а) помнить, какие модификаторы критичны для создаваемых элементов и доставать их вручную при помощи
[...].reduce( ... liveBlock.getMod ...)
или как-то типа, (б) использоватьliveBlock._modCache
, (в) лепить ещё один велосипед, выковыривающий все модификаторы из имён классов -- по сути, восстанавливая функционал того жеgetMods
. Как правильно поступать?Скорее всего это говорит о том, что проблема была всегда, но старый API позволял замести ее под ковер. Как раз про это я говорю, что после миграции код вынужден выпрямляться в тех местах, где раньше можно было срезать углы. Это скорее хорошо.
Как вариант можно решить через модификаторы: в данных приходит название нужного блока, оно же прокидывается в модификатор, тогда модификатор точно знает, какой блок требуется.
Судя по формулировке вопроса, нужные модификаторы обязаны быть заранее известны, так что я за первый вариант — перебирать список и проверять, установлен ли такой модификатор.
@tadatuta
А вот такой эффект с bemhtml:
Если в шаблоне указано
js()(true),
, то мои параметры, указываемые при создании блока (js : { param1 : ..., ... }
) просто выбрасываются. Сначала обнаружил это в своих блоках, там код переделал. Но сейчас попалось в библиотечных (button). Как быть?Значит ли это, что теперь не рекомендуется хранить свои параметры в чужих блоках (если явно не разрешено автором)? Или это баг?
Если я правильно понял о чем речь, то это уже не с bem-core связано, а с мажором в bem-xjst. Там добавились новые режимы
add*
, в частности в данном случае нуженaddJs()
. А простоjs()
теперь перетирает, а не добавляет.Ну вот, а я опять навелосипедил. Хорошо, много не успел.
А что же делать с библиотечными (bem-components@6.0.0) блоками, у которых в behtml стоит именно
js()(true)
? Отныне и впредь использовать параметры только в своих блоках?Пока миксую элемент своего блока, в который укладываю нужные параметры. Примерно так:
Позже вытаскиваю
myParam
из миксованного элемента. Немного неудобно, но вроде логичнее. (UPD Хотя в коде выглядит странно: работаю с модификаторами у button, а за параметрами обращаюсь к своему блоку... Кхм...)На самом деле в 99% случаев нужно использовать add*-режимы и все будет ок. Перекрывать нужно достаточно редко.
А вот ещё: переделываю своё решение для иерархических меню. У меня была пара доопределённых модификатором
tree:true
блоков menu и menu-item. Сейчас переклеиваю menu-item в menu__item. Т.е., у меня получается структураmenu/_tree/__item
:Как правильно определять модуль для элемента блока menu:tree и в какую папку с какими именами раскладывать файлы? Правильно ли понимаю, что это должно быть
menu/_tree/__item/menu_tree__item.*
?Надо ли прокидывать к элементу модификатор
tree
, как раньше? Или можно как-то доопределить элемент блока с модификатором? Как это дожно выглядеть?На FS будет
menu/__item/_three/menu__item_three.*
.Но нужно ли прокидывать модификатор зависит от задач, которые нужно решить, универсального ответа не может быть.
Я правильно понимаю, что
menu/__item/_three/menu__item_tree.*
-- это item:tree для menu? Т.е., что модификатор именно на элементе, а не на блоке? Это же именно прокидывание модификатора к элементу?Нельзя ли описывать элемент для блока с модификатором? Вот так:
menu/_tree/__item/menu_tree__item.*
?Такая схема у меня тоже получилась:
deps:
Файлы приходится класть в другую папку (
menu/__item/_tree/menu__item_tree.*
):BEMHTML:
JS:
STYL:
Имел в виду, что весь функционал, связанный с реализацией
tree
будет расположен в одной папке (menu/_tree
) -- почему-то думалось, что теперь это будет проще.По смыслу, если реализация элемента имеет смысл только в контексте модификатора блока, то её следует писать прямо в файле самого модификатора блока. Вынесение в отдельные файлы предполагает, что они могут быть использованы независимо.
@tadatuta Можено ещё раз попробовать уточнить: Есть ли возможность указывать параметры input-элементам из bem-components? В библиотечных шаблонах везде стоит
js()(true)
, которое перезаписывает все переданные извнеjs
иaddJs
. Это теперь невозможно/запрещено?@lilliputten тот факт, что в библиотеке
js()(true)
не должен мешать на уровне проекта добавить параметры черезaddJS()
. по крайней мере так должно быть и это работает в песочнице: https://goo.gl/JHysl5Если на проекте не срабатывает, возможно, где-то закрался баг. Буду благодарен за репозиторий, где можно воспроизвести.
Имел в виду передачу параметров из описания блока. Т.е., в рассматриваемой песочнице в левой части было бы:
Так же ведь больше не работает?
Т.е., работает, но только если в шаблонах используется не
js
, аaddJs
. В bem-components же традицонно именноjs()(true)
. Это конец обеда, да?Все, до меня дошло, наконец. Это баг на стороне bem-components, будем чинить, спасибо за настойчивость!
Ещё про зависимости и правильный поиск: как поступать, если блок должен создавать/искать элементы внутри себя, а элементы хотят получить доступ к методам блока (ну и, соответственно, найти его)?
Т.е., по идее и блоку надо иметь элементы в зависимостях, и элементам -- сам блок? Это же Circular dependences получатся?
Блоку элементы нужно, а элементам блок — нет, это получится автоматически. И у элементов есть метод
_block
, чтобы получить родительский блок.@tadatuta Ещё про перекрёстные зависимости "по-правильному".
Если не вот такое:
А взаимоотношения "блоков-детей" и "блока-хозяина", примерно так:
И при этом хозяин должен найти детей и управлять ими (
this.findChildBlocks(Child)
), а дети хотят иметь доступ к хозяину и передавать информацию (this.findParentBlock(Owner)
).Я правильно понимаю, что такой подход концептуально неправильным и решается, например, используя механизм событий? Или это ещё б.-м. в рамках и как-то реализуемо?
Да, все так. Родитель «знает» про детей, а дети про родителя знать не должны. События — вполне хороший способ обеспечить связь и избежать связанности.