# 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-реалізацію блоку;
  * полегшити навігацію по файловій структурі проекту.
