# JavaScript по БЭМ

В БЭМ-методологии JavaScript используется для «оживления» веб-страницы и рассматривается как одна из [технологий реализации](../key-concepts/key-concepts.ru.md#Технология-реализации) блока.

В БЭМ к JavaScript применяются [дополнительные правила](../bem-js-principles/bem-js-principles.ru.md), которые позволяют реализовать все идеи компонентного подхода БЭМ-методологии.

## Основные принципы компонентного подхода в JavaScript по БЭМ

JavaScript — это одна из технологий реализации блока, поэтому в работе с JavaScript могут соблюдаться основные идеи БЭМ-методологии:
  * [Единая предметная область](#Единая-предметная-область) — использование блоков, элементов и модификаторов, названных по общим [правилам именования](../naming-convention/naming-convention.ru.md).
  * [Разделение кода на части](#Разделение-кода-на-части) и одинаковые [правила организации файловой структуры БЭМ-проекта](../filesystem/filesystem.ru.md).
  * [Разделение кода по уровням переопределения и использование сборки](#Работа-с-уровнями-переопределения).

### Единая предметная область

В веб-разработке финальный продукт (например, веб-страница) состоит из разных технологий (HTML, CSS, JS и т.д.). В БЭМ для работы во всех технологиях используются единые термины и подходы к реализации. Таким образом вся команда БЭМ-проекта получает единый язык для общения, то есть работает в терминах блоков, элементов и модификаторов.

Так, JavaScript-реализация блоков не оперирует понятиями DOM-элементов, а использует следующий уровень абстракции — [БЭМ-дерево](../key-concepts/key-concepts.ru.md#БЭМ-дерево). Это позволяет не опираться на классы, а независимо описывать поведение блоков и их опциональных элементов. Модификаторы в JavaScript используются для выражения логики работы блока или элемента (по аналогии с CSS, где с помощью модификаторов задается внешний вид). Поведение блоков и элементов описывается в JavaScript как набор состояний.

Применение единых понятий во всех технологиях позволяет реализовать в JavaScript различные хелперы для работы с компонентами и отказаться от жесткого кодирования имен блоков и разделителей. Такой подход дает возможность, например, найти внутри блока все элементы с определенным именем и выставить им модификатор, проверить его значение.

**Пример**

Рассмотрим пример всплывающего окна (`popup`).
Показывать всплывающее окно можно различными способами:

* Воспользоваться распространенным решением и добавлять соответствующий класс. Такой способ не всегда удобен, так как необходимо жестко прописывать имя блока в коде.

  ```js
  document.querySelector('.button')
    .addEventListener('click', function() {
      document.querySelector('.popup').classList.toggle('popup_visible');
  }, false);
  ```

* Воспользоваться принципами БЭМ и оперировать не классами, а блоками, элементами и модификаторами.
  В таком случае поиск компонента выполняется не по классу, а по имени блока, который в проекте может выражаться не только классом, но и тегом, атрибутом и т.д. Отображение всплывающего окна (перевод блока `popup` в состояние `visible`) также осуществляется не по классу, а с помощью модификатора.

  ```js
  block('button').click(function() {
      block('popup').toggleMod('visible');
  });
  ```

  > **Обратите внимание!** Для примеров, написанных по БЭМ-методологии, используется псевдокод. Реальные примеры реализации представлены в документации к [i-bem.js](https://ru.bem.info/technology/i-bem/v2/i-bem-js/).

Использование единой предметной области дает возможность на более высоком уровне взаимодействовать с компонентами.


#### Работа с модификаторами

Модификаторы могут задавать блокам определенные состояния. Логика работы блока реализуется в JavaScript и описывается с помощью состояний. Перевод блока в другое состояние может производиться при помощи установки/снятия модификатора. Изменение модификатора создает событие, которое можно использовать для работы с блоком.

Например, чтобы отметить чекбокс, блоку `checkbox` нужно установить модификатор `checked` в значение `true`.

В БЭМ-проекте нельзя изменять состояния в режиме runtime с помощью модификатора, напрямую меняя CSS-класс на соответствующем DOM-узле. Для корректной работы JavaScript все манипуляции с модификаторами должны производиться при помощи методов-хелперов.

> Примеры реализации доступны в документации к [i-bem.js](https://ru.bem.info/technology/i-bem/current/i-bem-js-mods/).

##### Реакция на изменение модификаторов

Переход блока из одного состояния в другое часто вызывает изменения в его внешнем виде. Если в CSS внешний вид блока задается с помощью модификатора, то изменение состояния блока, вызванное тем же модификатором, автоматически применит все необходимые стили.

В БЭМ реакция на установку/снятие модификатора описывается [декларативно](../bem-js-principles/bem-js-principles.ru.md#Декларативный-стиль). Так, например, если в CSS во время исполнения появляется какой-то дополнительный класс (модификатор), то все свойства этого модификатора автоматически применяются к DOM-узлу, на который этот класс установлен. В JavaScript происходит то же самое: если появляется модификатор (добавляется новый класс к DOM-узлу), то вся функциональность, свойственная этому модификатору, применяется. Если модификатор исчезает, функциональность отключается.

Чтобы динамически изменять состояния блоков и элементов, используются специальные методы для установки и снятия модификаторов.

> Примеры реализации доступны в документации к [i-bem.js](https://ru.bem.info/technology/i-bem/v2/i-bem-js-mods/).

**Пример**

Рассмотрим форму отправки сообщения. Должно выполняться условие: если введен неправильный email, кнопка отправки (блок `button`) становится недоступна (получает модификатор `button_disabled`).

Можно жестко прописать все условия в коде и постоянно выполнять проверку. Такой подход не удобен, так как любое изменение потребует изменений в коде вручную.

Можно задекларировать поведение блока и получить возможность перекрывать каждый модификатор отдельно на новом уровне переопределения. В [декларации](https://ru.bem.info/technology/i-bem/current/i-bem-js-decl/) можно указать, как блок или элемент должен отреагировать на изменение модификатора.

```js
block('button').onSetMod({
    focused: {
        true: this.onFocus,
        '': this.onBlur
    }
});
```

Такой подход дает возможность:
* Реагировать на модификатор независимо от способа его установки/снятия (через JavaScript API: `block('button').setMod('focused')` или пользователь установил/снял фокус курсором).
* Определять каждому состоянию свой внешний вид, добавив стили модификатору.
* Изменять или полностью перекрывать поведение блока с помощью [уровней переопределения](#Работа-с-уровнями-переопределения).

### Разделение кода на части

К JavaScript могут применяться основные принципы организации и хранения кода по БЭМ-методологии:
  * разделение кода на отдельные части — логика работы каждого блока, его опциональных элементов и модификаторов описывается в отдельных файлах;
  * JavaScript-файлы для каждого компонента хранятся в соответствии с [правилами организации файловой структуры](../filesystem/filesystem.ru.md) БЭМ-проекта.

**Пример**

Рассмотрим пример логотипа (блок `logo`), реализованного в двух технологиях: шаблоне и стилях.

HTML-реализация блока:

```html
<a class="logo" href="/">Ваша крутая компания</a>
```
CSS-реализация блока:

```css
.logo {
    width: 150px;
    height: 100px;
}
```
Блок `logo` в файловой структуре проекта:

```files
logo/
    logo.css   # Внешний вид блока
    logo.tmpl  # Шаблоны для генерации HTML-представления блока
```

Добавим блоку `logo` JavaScript-функциональность: теперь нажатие на логотип вызывает какое-то действие. Согласно БЭМ-методологии новое поведение блока `logo` будет реализовано следующим образом:
  * в отдельном файле;
  * имя файла будет соответствовать имени блока с расширением `.js`;
  * файл `logo.js` будет находится в директории блока `logo/`.

JavaScript-реализация блока:

```js
document.querySelector('.logo').addEventListener('click', doSomething, false);
```

Файл `logo.js` в файловой структуре блока:

```files
logo/
    logo.css   # Внешний вид блока
    logo.tmpl  # Шаблоны для генерации HTML-представления блока
    logo.js    # Динамическое поведение блока в браузере
```

Разделение кода на части и строгая организация файловой системы проекта позволяет не только облегчить навигацию по проекту и повторное использование или перенос компонентов, но и работать с уровнями переопределения для JavaScript и использовать сборку.

### Работа с уровнями переопределения

В описании БЭМ-методологии приведено [много примеров](../filesystem/filesystem.ru.md#Примеры-использования-уровней-переопределения), где конечная CSS-реализация блока собирается с разных уровней переопределения. Применение принципов БЭМ-методологии к JavaScript позволяет аналогичным образом разделять поведение блоков по разным уровням:
  * реализовывать новую функциональность блока на другом уровне переопределения, сохраняя предыдущее поведение блока, наследовать и дополнять его (делать super call);
  * полностью перекрывать поведение блока (переопределять);
  * добавлять новые блоки с новой функциональностью, которых не было на предыдущих уровнях.

С помощью уровней переопределения можно создать универсальную JavaScript-библиотеку блоков и изменять ее на проектном уровне. Затем использовать сборку и включать в проект только необходимое поведение блоков.

**Пример**

Вернемся к примеру формы отправки сообщения:

```js
block('button').onSetMod({
    focused: {
        true: this.onFocus,
        '': this.onBlur
    }
});
```

Запись с стиле БЭМ позволяет:

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

  ```js
  block('button').onSetMod({
      focused: {
          true: this.someCustomOnFocused
      }
  });
  ```
* Добавлять или частично изменять поведение блока на другом уровне переопределения.

  ```js
  block('button').onSetMod({
      focused: {
          true: function() {
              this.__base.apply(this, arguments);
              this.someCustomOnFocused();
          }
      }
  });
  ```

> Для работы с уровнями переопределения в БЭМ можно использовать специализированный фреймворк, например, [i-bem.js](https://ru.bem.info/technology/i-bem/current/i-bem-js/), так как он создан по требованиям БЭМ-методологии.

## Как перейти на JavaScript по БЭМ

Самый быстрый путь — начать применять принципы БЭМ-методологии в своем проекте и получать первые результаты без использования специализированного фреймворка. Как это сделать на практике показано в статье [БЭМ — это не только про CSS](https://ru.bem.info/forum/163/) с примерами на jQuery.

Чтобы реализовать сразу все идеи БЭМ в вашем проекте, необходимо использовать фреймворк [i-bem.js](https://ru.bem.info/technology/i-bem/current/i-bem-js/):
  * работать в [единых терминах](#Единая-предметная-область) блоков, элементов и модификаторов во всех технологиях;
  * создавать независимые компоненты — блоки — на уровне JavaScript;
  * изменять поведение блоков, элементов и модификаторов с помощью уровней переопределения по аналогии с CSS;
  * повторно использовать блоки, переносить их между проектами;
  * облегчить и ускорить разработку и отладку проекта за счет несвязанности компонентов и возможности разрабатывать поблочно;
  * включать в сборку только нужную JavaScript-реализацию блока;
  * облегчить навигацию по файловой структуре проекта.
