Всем привет!
Я только учусь и все пытаюсь разобраться с 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, верно?Да, верно. Будут трудности - спрашивай.