Всем привет!
Я только учусь и все пытаюсь разобраться с i-bem
.
- Как правильно воспроизвести такую логику: есть два блока, первый из них через JavaScript влияет на другой. Например, кнопка меню на мобильной версии сайта показывает и скрывает меню. Я хотел сделать таким образом, первому блоку передаются параметры, название блока и id, над которым будут совершаться какие-то действия:
js: {
toggledBlock: {
block: 'nav',
id: 'menu'
}
}
Дальше я пытаюсь по этим данным найти блок:
var targetID = this.params.toggledBlock.id;
var targetBlock = this.params.toggledBlock.block;
var toggledBlock = this.findBlocksOutside(targetBlock).filter(function(block) {
return block.params.id = targetID;
});
Эти блоки у меня стоят рядом; findBlocksOutside
ничего не находит, остальные методы findBlock(s)*
тоже ничего не находят. У меня возник такой вопрос, почему же вообще существуют такие методы как findBlocksOutside
, findBlocksInside
, findBlocksOn
, не противоречат они самой методологии, что блок должен знать где находится другой блок? Не проще ли иметь метод find
, который просто находит необходимый блок в независимости от местаположения? Как же правильно решить задачу с меню, и как правильно применять методы findBlock*
?
- Второй вопрос по документации по i-bem, можно ли как-то ее понять? =) Сколько я ее не читал, так я с ней и не подружился. Можно ли найти примеры использования методов i-bem? Каждый раз как я пытаюсь написать что-то на JavaScript я застапариваюсь на простых вещах. Например метод
this.setMod([elem], modName, modVal)
, я бился несколько часов пытаясь проставить модификатор элементу:
this.setMod('elem', 'someMod', 'itsValue');
В первый раз, когда используешь этот метод, хочется написать именно таким образом, и в голову не приходит, что на месте 'elem'
должен быть явно указанный элемент, this.elem('elem')
. В документации при первой встречи метода setMod
ничего не сказано про то, что же передается этому методу.
У меня каждый раз возникают проблемы при использовании какого-то методы i-bem. Кажется из названия метода ясно как он работает, пытаешься его использовать, понимаешь, что понятия не имеешь как он работает, лезешь в документацию, в документации ничего не написано.
Также возникает вопрос, если есть методы findBlocks*
, которые возвращают массив блоков, то почему нет метода, который возвращает массив элементов?
@bradbenetton
Способов решения есть несколько. Предложу начать с теоретической части, а нижу отвечу про конкретные варианты в контексте i-bem: https://ru.bem.info/forum/issues/163/
Как должно было стать понятно из поста «БЭМ — это не только про CSS», методология вполне допускает общение блоков друг с другом и предлагает ряд решений, чтобы реализация оказалась расширяемой и позволяла реиспользование кода.
Если рассматривать вариант с поиском другого блока в DOM-дереве, то по методологии блок может знать про примиксованные к нему блоки (
findBlockOn
) и своих детей (findBlockInside
). Единственное исключение — это методfindBlockOutside
, который на самом деле действительно противоречит методологии и его использование не рекомендуется.Однако зачастую задачу взаимодействия с другими блоками можно решить без использования findBlock-методов. Например, с помощью событий или каналов (pub/sub):
Подробнее про методы
events__channels
см. https://ru.bem.info/libs/bem-core/v2.6.0/desktop/events/jsdoc/findBlockInside
иfindBlockOn
в простом случае принимают имя блока в виде строки либо объект вида{ block: 'b1', modName: 'm1', modVal: 'v1' }
и возвращают первый найденный блок внутри себя или на собственном DOM-узле соответственно.Кроме того, они позволяют передавать первый опциональный аргумент с именем элемента в виде строки или jQuery-коллекции, в рамках которого будет происходить поиск.
Сигнатура: findBlockInside([elem], block) → {BEMDOM} [elem] {String | jQuery} Элемент блока block {String | Object} Имя или объект с полями block, modName, modVal блока, который требуется найти
Как я уже писал, использовать
findBlockOutside
не рекомендуется, но логика его работы следующая: он находит блоки строго вверх по DOM-дереву. Т.е. чтобы «достучаться» до блока-сиблинга, потребуется сделатьthis.findBlockOutside('ближайший-общий-родитель').findBlockInside('целевой-блок')
.Методы findBlocks* работают аналогично, но возвращают массив всех подходящих блоков, с которым дальше предполагается использование, например,
forEach()
.Предложу туториал и исходники в bem-components.
Чтобы понять, что каждый метод ожидает на вход, стоит смотреть в JSDoc. Например, для метода
setMod
там видно, что опциональный аргументelem
должен быть объектом.Мы потихоньку работаем над улучшением документации, но, к сожалению, несколько ограничены в ресурсах :(
Всегда остается самый надежный способ — заглянуть в исходики:
Ну и на форуме всегда подскажут.
Дело в том, что методы
elem()
иfindElem()
возвращают jQuery-коллекцию, т.е. по смыслу как раз всегда массив. И работать с элементами нужно именно как с jQuery-коллекциями:this.elem('e1').hide();
. Другое дело, что чаще всего вместо этого подойдетthis.setMod(this.elem('e1'), 'hidden')
+ в CSS.b1__e1_hidden { display: none }
.Я подобное меню с кнопкой считаю одним блоком, а не двумя независимыми. Свою реализацию сделал именно как один блок на нескольких элементах
@Guria Я обращал внимание на этот способ, но на самом деле не понял как же его реализовать. Грубо говоря в
BEMJSON
нужно объявить два одинаковых блока и присвоить им вjs
одинаковыеid
, верно?Да, верно. Будут трудности - спрашивай.