Вертикальное меню списком

{ block: 'b-menu-vert' }

Блок, создает разметку для вертикального меню. Построен на основе блока-хелпера i-menu.

Простое вертикальное меню

В простейшем случае в BEMJSON достаточно объявить блок и перечислить его элементы item в свойстве content:

{
  block: 'b-menu-vert',
  content: [
    {
      elem: 'item',
      content: 'Index'
    },
    {
      elem: 'item',
      content: 'Contacts'
    },
    ...
  ]
}

В получившемся HTML появляются не только узлы для блока и явно заданных элементов item, но и разметка для элементов layout и layout-unit, которые отвечают за геометрическую отрисовку блока.

В качестве контента элементов item в простых случаях используются ссылки:

{
  block: 'b-menu-vert',
  content: [
    {
      elem: 'item',
      content: {
        block: 'b-link',
        url: 'http://yandex.com',
        content: 'Index'
      }
    },
    ...
  ]
}

У одного из элементов 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: { ... }
  ]
}

Для отображения заголовка меню (элемент title), в BEMJSON необходимо указать свойство 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: { ... }
  ]
}

Предусмотрена возможность создания пустого элемента списка для визуального разделения одних пунктов от других. За это отвечает элемент separator. Для этого на уровне переопределения проекта нужно задать CSS-правила для него. Чаще всего separator представляют в виде горизонтальной черты.

{
  block: 'b-menu-vert',
  content: [
    {
      elem: 'item',
      content: { ... }
    },
    {
      elem: 'separator'
    },
    {
      elem: 'item',
      content: { ... }
    }
  ]
}

Вертикальное js-меню с псевдоссылками

В BEMJSON доопределяем обычные ссылки до псевдо-ссылок, используя модификатор { pseudo: 'yes' }:

{
  block: 'b-menu-vert',
  content: [
    {
      elem: 'item',
      elemMods: { 'state': 'current' },
      content: {
        block: 'b-link',
        mods: { 'pseudo': 'yes' },
        content: 'First 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'
      }
    },
    ...
  ]
}

Вертикальное js-меню со сложным контентом

Пункты меню могут содержать не один, а несколько блоков.

Поскольку реакция на клик необходима для всего содержания пункта меню, элемент 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: '/',
            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'
            }
          ]
        }
      }
    },
    ...
  ]
}

Кроме элемента item-selector здесь используется свойство item-content, описывающее элемент item-content с содержанием, которое показывается или скрывается в зависимости от кликов по элементу item-selector.

Элемент trigger-icon используется только для обозначения иконки. Не является обязательным элементом.

По умолчанию элемент 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: [ ... ]

Вложенные меню

BEMJSON позволяет вкладывать одни блоки в другие. Содержанием пункта меню может быть другое меню, и тогда естественным образом образуется вложенность.
Такое использование меню создаст в DOM-дереве два блока (и два узла ul), которые будут вести себя соответственно.

Если есть необходимость визуально представить меню как вложенное, но функционально — как один блок (например, со сквозным поведением активного пункта меню), нужно воспользоваться элементом submenu.

Элемент submenu должен содержаться в элементе item-content и включать в себя описание элементов item для вложеннего меню.

Элементы
__item

Элемент меню

{ elem: 'item' }

Элемент вертикального меню, может содержать любой контент, чаще всего это ссылки или псевдо-ссылки.
Имеет состояния: [ current, disabled ]

__item-content

Элемент, который показывается или скрывается в зависимости от кликов

{ elem: 'item-content' }

Не используется без элемента item-selector. По умолчанию невидим.

__item-content_visibility

__item-content_visibility_visible
{ elemMods: { 'visibility': 'visible' } }

Элемент виден

Добавление этого модификатора делает видимым элемент item-content.

__item-selector

Элемент для реакции на клик

{ elem: 'item-selector' }

Этот элемент появляется в меню, когда требуется реакция на клик по пункту меню.
Реакция на клик может понадобиться, если при выборе пункта меню нужно что-то сделать на клиенте. Например, загрузить контент по AJAX.

Реакция есть только на клик левой кнопкой мыши. В результате клика соответствующий пункт меню (элемент item) приобретает модификатор { state: 'current' }, то есть пункт меню становится «выделенным» (текущим). Предыдущий выделенный пункт меню в то же время теряет модификатор state.
В базовой CSS-реализации блока не предоставляется код для визуального выделения текущего пункта меню. Такой код можно реализовать на собственном уровне переопределения.

Элемент может быть представлен в DOM отдельным узлом (span) или быть смиксованным с другим блоком, чаще всего с псевдо-ссылкой.

__separator

Визуальный разделитель между пунктами меню

{ elem: 'separator' }
__submenu

Контейнер для пунктов вложенного меню

{ elem: 'submenu' }

Используется в случае, когда необходимо представить вложенное меню частью списка «меню-родителя».

__title

Заголовок вертикального меню

{ elem: 'title' }

Опциональный элемент. В HTML представлен тегом h3, выводится перед списком (ul).

__trigger

Элемент, скрывает/отображает вложенное меню

{ elem: 'trigger' }

Может содержать внутри себя опциональный элемент trigger-icon, который используется для отображения иконок.

Примеры

Простое вертикальное меню

исходный кодскомпилированный код

JS-меню, переключающее активный элемент

исходный кодуровень преопределенияскомпилированный код

Вертикальное меню с глубоко вложенным триггером

исходный кодуровень преопределенияскомпилированный код