В простейшем случае в BEMJSON достаточно объявить блок и перечислить его элементы item в свойстве content:
В получившемся HTML появляются не только узлы для блока и явно заданных элементов item, но и разметка для элементов layout и layout-unit. Эти элементы отвечают за геометрическую отрисовку блока.
В качестве контента элементов item в простых случаях используются ссылки:
{
block: 'b-menu-vert',
content: [
{
elem: 'item',
content: {
block: 'b-link',
url: 'http://yandex.com',
content: 'Index'
}
},
{
elem: 'item',
content: {
block: 'b-link',
url: 'http://google.com',
content: 'Backyard'
}
},
...
]
}Кроме того, у одного из элементов item может быть модификатор { state : 'current' }, отмечающий выделенный пункт меню. Модификатор используется как для визуального выделения пункта при помощи CSS-правил для этого модификатора, так и для описания функционального поведения.
{
block: 'b-menu-vert',
content: [
{
elem: 'item',
elemMods: { state: 'current' },
content: {
block: 'b-link',
url: 'http://yandex.com',
content: 'Index'
}
},
{
elem: 'item',
content: {
block: 'b-link',
url: 'http://google.com',
content: 'Backyard'
}
},
...
]
}
В BEMJSON описании меню может быть указано свойство title, задающее элемент title для заголовка меню:
{
block: 'b-menu-vert',
title: {
elem: 'title',
content: 'Menu title'
},
content: [
{
elem: 'item',
elemMods: { state: 'current' },
content: {
block: 'b-link',
url: 'http://yandex.com',
content: 'Index'
}
},
{
elem: 'item',
content: {
block: 'b-link',
url: 'http://google.com',
content: 'Backyard'
}
},
...
]
}
Предусмотрена и возможность создания пустого элемента списка для отделения одних пунктов меню от других. За это отвечает элемент separator.
На уровне переопределения проекта можно задать CSS-правила для такого элемента. Чаще всего его представляют в виде горизонтальной черты.
{
block: 'b-menu-vert',
content: [
{
elem: 'item',
elemMods: { state: 'current' },
content: {
block: 'b-link',
url: 'http://yandex.com',
content: 'Index'
}
},
{
elem: 'separator'
},
{
elem: 'item',
content: {
block: 'b-link',
url: 'http://google.com',
content: 'Backyard'
}
},
...
]
}Пример простого меню со ссылками содержится и в рпепозитории библиотеки bem-bl.
Вертикальное js-меню с псевдо-ссылками
Если вместо ссылок нужно использовать псевдо-ссылки, BEMJSON меню должен отличаться содержанием элементов item:
{
block: 'b-menu-vert',
content: [
{
elem: 'item',
elemMods: { 'state' : 'current' },
content: {
block: 'b-link',
mods : { 'pseudo' : 'yes' },
url: '/',
content: 'First point'
}
},
{
elem: 'item',
content: {
block: 'b-link',
mods : { 'pseudo' : 'yes'},
url: '/',
content: 'Second point'
}
},
...
]
}Кроме внешнего вида, js-меню отличается и клиентской функциональностью: оно способно по клику левой кнопкой мыши переключать соответствующий пункт меню в состояние { state : 'current' } и генерировать на js-объекте, соответствующем блоку, событие о факте переключения пункта меню.
Для использования этой функциональности необходимо определить, где у меню будут расположены элементы item-selector, реагирующие на клик. Эти элементы нарочно сделаны несовпадающими с элементами item, потому что чаще всего сам пункт меню больше по размеру, чем его активная область.
Элемент item-selector можно использовать как сам по себе, так и примешивая его к другим элементам или блокам. В данном случае можно сделать mix с псевдо-ссылками:
{
block: 'b-menu-vert',
content: [
{
elem: 'item',
elemMods: { 'state' : 'current' },
content: {
block: 'b-link',
mods : { 'pseudo' : 'yes' },
mix: [{ block: 'b-menu-vert', elem: 'item-selector'}],
url: '/',
content: 'First point'
}
},
{
elem: 'item',
content: {
block: 'b-link',
mods : { 'pseudo' : 'yes'},
mix: [{ block: 'b-menu-vert', elem: 'item-selector'}],
url: '/',
content: 'Second point'
}
},
...
]
}
Пример простого вертикального js-меню есть в папке блока в библиотеке bem-bl.
Вертикальное js-меню со сложным контентом
Пункты меню могут содержать не один, а несколько блоков. В библиотеке bem-bl есть пример такого меню. Его пункты помимо ссылок содержат иконки.
Поскольку реакция на клик необходима для всего содержания пункта меню, элемент item-selector используется в таком случае в явном виде, являясь контейнером для содержания пункта меню. В этом случае он представлен в DOM-дереве узлом span:
{
elem: 'item',
content: {
elem: 'item-selector',
content: [
{
block: 'b-link',
mods : { 'pseudo' : 'yes', 'inner' : 'yes' },
mix: [{ block: 'b-menu-vert', elem: 'item-selector'}],
url: '/',
content: [
{
block: 'b-icon',
url: 'http://yandex.st/lego/_/Kx6F6RQnQFitm0qRxX7vpvfP0K0.png',
alt: 'Yandex favicon'
},
{
elem: 'inner',
content: 'Second point'
}
]
},
' One more element here'
]
}
}
Раскрывающееся вертикальное js-меню
Переключение активного пункта меню - не единственная реализованная динамическая функциональность. Пункты меню также могут содержать элементы trigger, клик по которым открывает или скрывает дочерний контент. С помощью таких элементов можно реализовать скрывающиеся вложенные меню.
Так же, как и элемент item-selector, элемент trigger может использоваться не явно, а через mix.
{
block: 'b-menu-vert',
content: [
{
elem: 'item',
elemMods: { state: 'current' },
content: 'Videos'
},
{
elem: 'item',
content: {
block: 'b-link',
mods: { pseudo: 'yes', inner: 'yes'},
mix: [{ block: 'b-menu-vert', elem: 'trigger'],
content: [
{
block: 'b-icon',
mix: [{ block: 'b-menu-vert', elem: 'trigger-icon' }],
alt: 'trigger'
},
{
elem: 'inner',
content: 'Images'
}
]
},
'item-content': {
elem: 'item-content',
content: {
block: 'b-menu-vert',
mods: { 'type' : 'submenu' },
content: [
{
elem: 'item',
content: 'Any size'
},
{
elem: 'item',
content: 'Large'
},
{
elem: 'item',
content: 'Medium'
}
]
}
}
},
{
elem: 'item',
content: {
block: 'b-link',
url: '/',
content: 'News'
}
}
]
}
Кроме элемента item-selector здесь используется свойство item-content, описывающее элемент item-content с содержанием, которое показывается или скрывается в зависимости от кликов по элементу item-selector.
Элемент trigger-icon используется только для обозначения иконки. На уровне переопределения соответствующего примера в bem-bl реализованы CSS-правила, показывающие одну иконку для триггера с открытым состоянием и другую для триггера с закрытым состоянием.
По умолчанию элемент trigger не содержит модификатора state, а элемент item-content не содержит модификатора visibility. В этом состоянии содержание элемента item-content не видно.
При клике на элементе trigger левой кнопкой мыши он приобретает модификатор { state : 'opened' }. Элемент item-content в это же время приобретает модификатор { visibility : 'visible' } и становится виден на странице.
Если нужно сразу показать вложенное меню раскрытым, эти модификаторы следует явно задать в BEMJSON-описании блока:
{
block: 'b-link',
mods: { pseudo: 'yes', inner: 'yes'},
mix: [{ block: 'b-menu-vert', elem: 'trigger', elemMods: { state: 'opened' }}],
content: [
...
}
'item-content': {
elem: 'item-content',
elemMods: { visibility: 'visible'},
content: ...
В библиотеке bem-bl также есть пример меню с неоднократной вложенностью триггеров.
Вложенные меню
BEMJSON позволяет вкладывать одни блоки в другие. Содержанием пункта меню может быть другое меню, и тогда естественным образом образуется вложенность.
Такое использование меню создаст в DOM-дереве два блока (и два узла ul), которые будут вести себя соответственно.
Если есть необходимость визуально представить меню как вложенное, но функционально - как один блок (например, со сквозным поведением активного пункта меню), нужно воспользоваться элементом submenu.
Элемент submenu должен содержаться в элементе item-content и включать в себя описание элементов item для "подменю".
Пример для вложенного меню в библиотеке bem-bl демонстрирует такое BEMJSON-описание.
Сквозные вложенные меню работают и с триггером, BEMJSON для такого случая можно посмотреть в соответствующем примере.