У БЕМ-методології JavaScript використовується для «пожвавлення» веб-сторінки і розглядається як одна з технологій реалізації блоку.
У БЕМ до JavaScript застосовуються додаткові правила, які дозволяють реалізувати всі ідеї компонентного підходу БЕМ-методології.
JavaScript — це одна з технологій реалізації блоку, тому в роботі з JavaScript можуть дотримуватися основні ідеї БЕМ-методології:
- Єдина предметна область — використання блоків, елементів і модифікаторів, названих за загальним правилами іменування.
- [Поділ коду на частини](#Поділ-коду на частини) і однакові правила організації файлової структури БЕМ-проекту.
- [Поділ коду за рівнями перевизначення і використання збірки](#Робота з рівнями-перевизначення).
У веб-розробці фінальний продукт (наприклад, веб-сторінка) складається з різних технологій (HTML, CSS, JS і т. д.). У БЕМ для роботи у всіх технологіях використовуються єдині терміни та підходи до реалізації. Таким чином вся команда БЕМ-проекту отримує єдиний мову для спілкування, тобто працює в термінах блоків, елементів і модифікаторів.
Так, JavaScript-реалізація блоків не оперує поняттями DOM-елементів, а використовує наступний рівень абстракції — БЕМ-дерево. Це дозволяє не спиратися на класи, а незалежно описувати поведінку блоків та їх опціональних елементів. Модифікатори JavaScript використовуються для вираження логіки роботи блоку або елемента (за аналогією з CSS, де з допомогою модифікаторів задається зовнішній вигляд). Поведінка блоків і елементів описується в JavaScript як набір станів.
Застосування єдиних понять у всіх технологіях дозволяє реалізувати в JavaScript різні хелпери для роботи з компонентами і відмовитися від жорсткого кодування імен блоків і роздільників. Такий підхід дає можливість, наприклад, знайти всередині блоку всі елементи з певним ім'ям і виставити їм модифікатор, перевірити його значення.
Приклад
Розглянемо приклад спливаючого вікна (popup).
Показувати спливаюче вікно можна різними способами:
-
Скористатися поширеним рішенням і додавати відповідний клас. Такий спосіб не завжди зручний, так як необхідно жорстко прописувати ім'я блоку в коді.
document.querySelector('.button') .addEventListener('click', function() { document.querySelector('.popup').classList.toggle('popup_visible'); }, false);
-
Скористатися принципами БЕМ і оперувати не класами, а блоками, елементами та модифікаторами. У такому випадку пошук компонента виконується не по класу, а по імені блоку, який у проекті може виражатися не тільки класом, але і тегом, атрибутом і т. д. Відображення спливаючого вікна (переклад блоку
popupстанvisible) також здійснюється не по класу, а з допомогою модифікатора.block('button').click(function() { block('popup').toggleMod('visible'); });
Зверніть увагу! Для прикладів, написаних за БЕМ-методології, що використовується псевдокод. Реальні приклади реалізації представлені у документації до i-bem.js.
Використання єдиної предметної області дає можливість на більш високому рівні взаємодіяти з компонентами.
Модифікатори можуть задавати блокам певні стани. Логіка роботи блоку реалізується в JavaScript і описується за допомогою станів. Переклад блоку в інший стан може проводитися за допомогою установки/зняття модифікатора. Зміна модифікатора створює подія, яку можна використовувати для роботи з блоком.
Наприклад, щоб відзначити чекбокс, блоку checkbox потрібно встановити модифікатор checked значення true.
У БЕМ-проекті не можна змінювати стану в режимі runtime з допомогою модифікатора, безпосередньо змінюючи CSS-клас на відповідному DOM-сайті. Для коректної роботи JavaScript всі маніпуляції з модифікаторами повинні проводитися за допомогою методів-хелперів.
Приклади реалізації доступні в документації до i-bem.js.
Перехід блоку з одного стану в інший часто викликає зміни в його зовнішньому вигляді. Якщо в CSS зовнішній вигляд блоку задається з допомогою модифікатора, то зміна стану блоку, викликане тим же модифікатором, автоматично застосує всі необхідні стилі.
У БЕМ реакція на встановлення/зняття модифікатора описується декларативно. Так, наприклад, якщо в CSS під час виконання з'являється якийсь додатковий клас (модифікатор), то всі властивості цього модифікатора автоматично застосовуються до DOM-вузла, на який цей клас встановлений. В JavaScript відбувається те ж саме: якщо з'являється модифікатор (додається новий клас до DOM-сайту), то вся функціональність, властива цьому модификатору, що застосовується. Якщо модифікатор зникає, функціональність відключається.
Щоб динамічно змінювати стану блоків і елементів, використовуються спеціальні методи для встановлення і зняття модифікаторів.
Приклади реалізації доступні в документації до i-bem.js.
Приклад
Розглянемо форму відправлення повідомлення. Повинно виконуватися умова: якщо введений неправильний email, кнопка відправки (блок button) стає недоступною (отримує модифікатор button_disabled).
Можна жорстко прописати всі умови в коді і постійно виконувати перевірку. Такий підхід не зручний, так як будь-яка зміна вимагає змін у коді вручну.
Можна задекларувати поведінка блоку і отримати можливість перекривати кожен модифікатор окремо на новому рівні перевизначення. В декларації можна вказати, як блок або елемент повинен відреагувати на зміну модифікатора.
block('button').onSetMod({
focused: {
true: this.onFocus,
'': this.onBlur
}
});Такий підхід дає можливість:
- Реагувати на модифікатор незалежно від способу його установки/зняття (через JavaScript API:
block('button').setMod('focused')або користувач встановив/зняв фокус курсором). - Визначати кожному станом свій зовнішній вигляд, додавши стилі модификатору.
- Змінювати або повністю перекривати поведінка блоку з допомогою [рівнів перевизначення](#Робота з рівнями-перевизначення).
До JavaScript можуть застосовуватись основні принципи організації і зберігання коду за БЕМ-методології:
- поділ коду на окремі частини — логіка роботи кожного блоку, його опціональних елементів і модифікаторів описується в окремих файлах;
- JavaScript-файли для кожного компонента зберігаються відповідно до правилами організації файлової структури БЕМ-проекту.
Приклад
Розглянемо приклад логотипу (блок logo), реалізованого в двох технологіях: шаблоні і стилях.
HTML-реалізація блоку:
<a class="logo" href="/">Ваша крута компанія</a>CSS-реалізація блоку:
.logo {
width: 150px;
height: 100px;
}Блок logo у файловій структурі проекту:
logo/
logo.css # Зовнішній вигляд блоку
logo.tmpl # Шаблони для генерації HTML-представлення блоку
Додамо блоку logo JavaScript-функціональність: тепер натискання на логотип викликає якусь дію. Згідно БЕМ-методології нове поведінка блоку logo буде реалізовано наступним чином:
- в окремому файлі;
- назва файлу повинна відповідати імені блоку з розширенням
.js; - файл
logo.jsбуде знаходиться в директорії блокуlogo/.
JavaScript-реалізація блоку:
document.querySelector('.logo').addEventListener('click', doSomething, false);Файл logo.js у файловій структурі блоку:
logo/
logo.css # Зовнішній вигляд блоку
logo.tmpl # Шаблони для генерації HTML-представлення блоку
logo.js # Динамічну поведінку блоку в браузері
Поділ коду на частини і сувора організація файлової структури проекту дозволяє не тільки полегшити навігацію по проекту і повторне використання або перенесення компонентів, але і працювати з рівнями перевизначення для JavaScript і використовувати збірку.
В описі БЕМ-методології приведено [багато прикладів](../filestructure/filestructure.ru.md#Приклади використання-рівнів-перевизначення), де кінцева CSS-реалізація блоку збирається з різних рівнів перевизначення. Застосування принципів БЕМ-методології до JavaScript дозволяє аналогічним чином розділяти поведінка блоків за різними рівнями:
- реалізовувати нову функціональність блоку на іншому рівні перевизначення, зберігаючи попереднє поведінка блоку, успадковувати і доповнювати його (робити super call);
- повністю перекривати поведінка блоку (змінити);
- додавати нові блоки з новою функціональністю, яких не було на попередніх рівнях.
З допомогою рівнів перевизначення можна створити універсальну JavaScript-бібліотеки блоків і змінювати її на проектному рівні. Потім використовувати збірку і включати в проект тільки необхідну поведінку блоків.
Приклад
Повернемося до прикладу форми надсилання повідомлення:
block('button').onSetMod({
focused: {
true: this.onFocus,
'': this.onBlur
}
});Запис у стилі БЕМ дозволяє:
-
Повністю перекривати поведінка блоку на іншому рівні перевизначення.
block('button').onSetMod({ focused: { true: this.someCustomOnFocused } });
-
Додавати або частково змінювати поведінку блоку на іншому рівні перевизначення.
block('button').onSetMod({ focused: { true: function() { this.__base.apply(this, arguments); this.someCustomOnFocused(); } } });
Для роботи з рівнями перевизначення БЕМ можна використовувати спеціалізований фреймворк, наприклад, i-bem.js, так як він створений за вимогами БЕМ-методології.
Найшвидший шлях — почати застосовувати принципи БЕМ-методології в своєму проекті і отримувати перші результати без використання спеціалізованого фреймворка. Як це зробити на практиці показано в статті БЕМ — це не тільки про CSS з прикладами на jQuery.
Щоб реалізувати всі ідеї БЕМ у вашому проекті, необхідно:
- працювати у [єдиних термінах](#Єдина-предметна область) блоків, елементів і модифікаторів у всіх технологіях;
- створювати незалежні компоненти — блоки — на рівні JavaScript;
- змінювати поведінку блоків, елементів і модифікаторів з допомогою рівнів перевизначення за аналогією з CSS;
- повторно використовувати блоки, переносити їх між проектами;
- полегшити і прискорити розробку і налагодження проекту за рахунок незв'язаності компонентів і можливості розробляти поблочно;
- включати в збірку тільки потрібну JavaScript-реалізацію блоку;
- полегшити навігацію по файловій структурі проекту.
- [Декларативний стиль](#Декларативний стиль)
- [Принципи ООП в JavaScript по БЕМ](#Принципи ООП-в-javascript-БЕМ)
- Подання динамічних блоків в DOM
- [Взаємодію блоків](#Взаємодія блоків)
- [Взаємодію блоку з його елементами](#Взаємодія-блоку з його елементами)
Декларативність JavaScript у БЕМ-проекті проявляється в наступному:
- Поведінка кожного блоку описується незалежно.
- Стану блоку задаються декларативно. При зміну станів автоматично викликається код, який задекларований для цього стану.
- Логіка роботи блоку описується як набір дій і умов, при яких ці дії необхідно виконувати. Це дозволяє розділяти функціональність блоку на окремі частини і використовувати рівні перевизначення.
Докладніше про застосування рівнів переопределния в JavaScript
У БЕМ-методології до JavaScript застосовуються основні принципи об'єктно-орієнтованого програмування (ООП).
У БЕМ JavaScript-реалізація одного блоку відокремлена від іншого. Кожен блок надає API для [взаємодії з іншими блоками](#Взаємодія блоків).
Декларація блоку дозволяє приховати його внутрішню реалізацію. Так як елементи завжди є внутрішньою реалізацією блоку, [звернення до них](#Взаємодія-блоку з його елементами) можливо тільки через API самого блоку.
Декларативне опис поведінки блоків дозволяє використовувати методи базового блоку всередині похідного, наслідувати їх. Новий блок може отримувати всі властивості і методи базового.
Також можна створювати ланцюжки спадкування — блок успадковується від іншого, який, у свою чергу, успадковується від третього і т. д.
Приклади реалізації доступні в документації до i-bem.js.
Блокам з JavaScript-реалізацією можуть відповідати вузли в HTML. У цьому випадку йдеться про те, що блоки мають DOM-подання.
У найпростішому випадку блок відповідає DOM-вузла один до одного. Однак DOM-вузол і блок — це не завжди одне і те ж. Можна розмістити кілька блоків на одному DOM-сайті (це називається мікс), а також реалізувати один блок на декількох DOM-вузлах.
Існують блоки без DOM-подання. В JavaScript вони представлені у вигляді об'єктів, що мають свої методи.
Приклади реалізації доступні в документації до i-bem.js.
БЕМ-методологія передбачає роботу з незалежними блоками. Однак на практиці повна незалежність блоків недосяжна.
Блоки можуть взаємодіяти один з одним за допомогою:
- Підписки на події інших примірників блоків.
- Підписки на зміни модифікаторів.
- Безпосереднього виклику методів інших примірників блоків або статичних методів класу іншого блоку.
- Будь патернів взаємодії. Наприклад, каналу подій: всі комунікації відбуваються завдяки повідомленнями, які компоненти публікують і слухають з допомогою посередника.
Приклади реалізації доступні в документації до i-bem.js.
БЕМ-методологія рекомендує вибудовувати взаємодію між блоками в ієрархічному порядку відповідно до їх розташуванням в DOM-дереві. Вкладений блок не повинен нічого знати про батьківському блоці, так як це порушує принцип незалежності компонентів.
Елемент — це внутрішня реалізація блоку. У БЕМ-методології прийнято реалізовувати додаткові хелпери блоку для роботи з його елементами. Звернення безпосередньо до елементу іншого блоку неможливо. Взаємодія з елементом відбувається тільки через API блоку, якому належить даний елемент.