Задача
У меня есть следующий bemhtml-шаблон на блок button:
{
tag: 'button',
content: (node, ctx) => ctx.icon ? [
{
elem: 'icon',
url: ctx.icon
},
ctx.text ? {
elem: 'text',
content: ctx.text
} : null
] : ctx.text || ctx.content
}
Здесь есть несколько вариантов генерации content. Также, есть блок form, у которого есть элемент send. Тело его шаблона выглядит следующим образом:
{
tag: 'button',
mix: {
block: 'button',
mods: {style: 'border', effect: 'invert'}
}
}
По сути, мне нужно иметь возможность написать в bemjson что-то вроде этого:
{
block: 'form',
content: [
{
elem: 'send',
icon: 'icon.svg',
text: 'Submit'
}
]
}
И я ожидаю результат:
<form class="form">
<button class="form__send button button_style_border button_effect_invert">
<svg class="button__icon" src="icon.svg"></svg>
<span class="button__text">Submit</span>
</button>
</form>
Что не является решением
Т.к. предикат на блок не срабатывает, находясь внутри микса, то никакой content не будет сгенерирован на основе icon и text. Предположим, я мог бы написать что-то вроде этого:
{
block: 'form',
content: [
{
block: 'button',
mods: {style: 'border', effect: 'invert'},
mix: {
block: 'form',
elem: 'send'
},
icon: 'icon.svg',
text: 'Submit'
}
]
}
Однако, реализация элемента form__send может изменится, и там могут быть совершенно другие модификаторы для button. Мне придется менять это везде в bemjson. По той же причине я не могу скопипастить реализацию content для button в form__send: реализация блока button может измениться.
В итоге
В идеале, мне нужно как-то задействовать поведение и button, и form__send в form__send. Т.к. через миксы это дело не работает, то я не знаю, что делать.
Да и вообще, поддержку шаблонов для миксов уже который год никак не могут выкатить. Как там в Яндексе без этого живут?
Шаблон не работает на миксах: mix — это лишь способ добавить к БЭМ-сущности CSS-классы другой сущности, он не отвечает за шаблонизацию.
Т. е. шаблон form/send/formsend.bemhtml.js будет выглядеть так:
+ не забыть добавить button в form/send/formsend.deps.js
P.S. Вместо
.replace()
можно использовать.content()
, тогда mix ненужен.P. P. S.
— Я поначалу тоже недоумевал. Но это действительно лишняя необходимость, которая лишь усложнит понимание того, откуда «протекла» шаблонизация. Приём с replace более наглядный и по сути единственный (не имею отношения к Яндексу, пишу на классическом стеке года 4).
Спс, как раз это и искал. Раньше пытался писать:
И это не работало. Просто не знал про replace. А с ним все действительно логично выходит.
Вот только есть проблема: icon, text и content мне нужно указывать в bemjson. А в replace они не попадают. Я мог бы написать что-то вроде:
Но, опять же, реализация блока button может измениться, и мне придется дописывать в реализацию form__send все изменения. Т.е. мне нужно прогнать контекст из bemjson в replace. Пробовал делать вот так:
И получал ошибку:
RangeError: Maximum call stack size exceeded
. Видимо, где-то зациклился вызов replace, только не пойму, где.А content мне не подходит, т.к. все должно быть на одном dom-узле.
Нет, это неправильное решение. При assign'е контекста в
button
прилетит elem: 'send' из form__send: https://bit.ly/3jgwcMP— Вам «шашечки» или «ехать»? Реализация любого файла может измениться. Явное лучше чем неявное. Я бы взял https://ru.bem.info/libraries/classic/bem-components/6.0.0/desktop/button/ и не парился.
Конечно, есть места, где я явно в шаблоне могу задать элементы контекста вроде icon или text. И если, например, название icon изменится на svg, то я буду менять реализацию в этих местах.
Но что делать, если у меня много элементов с "миксом" button через replace, не только form__send? Я хочу писать bemjson для них, как будто пишу его для button. Где-нибудь в документации я напишу, мол, поведение у этого элемента такое же, как у button.
В общем не подходит мне вариант, где я явно передаю различные параметры для button. Я думаю, лучше будет сделать следующим образом:
Где mixOpts - объект, в который я могу писать icon, text, и т.п.. И в итоге, мой bemjson будет выглядить как-то так:
Получается, что тут у меня разделены параметры для button и для form__send, и одно не попадет в другое.
А что касается предложенной вами реализации из bem-components, то ее я использовать не могу. Да и в целом, дело не в конкретных компонентах, есть еще несколько мест, где я столкнулся с подобной проблемой.