diff --git a/QuickStart.en.md b/QuickStart.en.md new file mode 100644 index 0000000..4075643 --- /dev/null +++ b/QuickStart.en.md @@ -0,0 +1,277 @@ +## Quick start for static page creation with BEM + +The article describes step-by-step implementation of a static page using [BEM methodology](https://bem.info/method/). + +## Expected outcome + +A page that contains an input field, a button, and a greeting text. A value from the input field will be added to the greeting text when the user clicks the button. + +![The greeting page](https://img-fotki.yandex.ru/get/16156/289488726.0/0_21888e_4908d18d_orig) + +## First steps to start + +### Minimal requirements + +An installed platform [Node.js 0.10](http://nodejs.org). + +### A local copy and environment setting + +A [template repository](https://github.com/bem/project-stub) is the quickest and easiest way to start your BEM project. It contains the minimal configuration files and folders. + +1. Make local copy of `project-stub`. + + **NB** The document describes an installation procedure based on the revision [13ae0e18ef8f48bc552b4944f7e5971c5b5f4768](https://github.com/bem/project-stub/ commit/13ae0e18ef8f48bc552b4944f7e5971c5b5f4768). The installation procedure of next versions may differ. + + ```bash + git clone https://github.com/bem/project-stub.git start-project + cd start-project + git checkout 13ae0e18ef8f48bc552b4944f7e5971c5b5f4768 + npm install + ``` + +2. Run a server with help of [ENB](https://ru.bem.info/tools/bem/enb-bem-techs/)(this article is available only in russian language). + + ```bash + node_modules/.bin/npm start + ``` + +3. Check the result on [http://localhost:8080/desktop.bundles/index/index.html](http://localhost:8080/desktop.bundles/index/index.html). + + A page with library blocks examples should open: + + ![A main page](https://img-fotki.yandex.ru/get/15493/289488726.0/0_218be7_cbbd5b69_orig) + +## Step-by-step instruction for the project creation + +1. [Create a page](#page_creation) + 1.1 [Describe the page in BEMJSON file](#BEMJSON_declaration) +2. [Create a block](#block_creation) +3. [Implement hello block](#block_hello_modification) + 3.1 [Use JavaScript technology](#JS_modification) + 3.2 [Use BEMHTML technology](#BEMHTML_modification) + 3.3 [Use CSS technology](#CSS_modification) + +When all steps have been completed you can watch the [result](#result). + + + +### 1. Create a page + +Pages source code are stored in the `start-project/desktop.bundles` directory. The main page `index.html` contains blocks implementations of [bem-components](https://en.bem.info/libs/bem-components/) library. + +Create a new page to start your own project. + +1. Create `hello` directory in the `desktop.bundles`. +2. Add `hello.bemjson.js` file into `hello` directory. + + + +#### 1.1 Describe the page in BEMJSON file + +A [BEMJSON file](https://en.bem.info/technology/bemjson/) describes a page structure in BEM terms: blocks, elements and modifiers. + +1. Add a description of `hello` block in the `desktop.bundles/hello/hello.bemjson.js` file. + **hello** block is an entity that will contain all necessary elements for the project. + + ```js + { + block: 'page', + title: 'hello', + head: [ + { elem: 'css', url: '_hello.css' } + ], + scripts: [{ elem: 'js', url: '_hello.js' }], + mods: { theme: 'islands' } + content: [ + { + block: 'hello' + } + ] + } + ``` + +2. Place `greeting` element with the greeting text (**content** field) into `hello` block. + **greeting** element is a sub-entity, that contains the greeting phrase and ready-made blocks implementations of `bem-components` library. + + ```js + content: [ + { + block: 'hello', + content: [ + { + elem: 'greeting', + content: 'Hello, %user%!' + `bem-components` library} + ] + } + ] + ``` + +3. To create an input field and a button use `input` and `button` blocks from `bem-components` library. Add these blocks to `greeting` element. + + ```js + ({ + block: 'page', + title: 'hello', + head: [ + { elem: 'css', url: '_hello.css' } + ], + scripts: [{ elem: 'js', url: '_hello.js' }], + mods: { theme: 'islands' }, + content: [ + { + block: 'hello', + content: [ + { + elem: 'greeting', + content: 'Hello, %user%!' + }, + { + block: 'input', + mods: { theme: 'islands', size: 'm' }, + name: 'name', + placeholder: 'User name' + }, + { + block : 'button', + mods : { theme : 'islands', size : 'm', type : 'submit' }, + text : 'Click' + } + ] + } + ] + }) + ``` + +To consider that the page shows all necessary objects, open [http://localhost:8080/desktop.bundles/hello/hello.html](http://localhost:8080/desktop.bundles/hello/hello.html). + +You can provide additional changes to existing blocks on your [redefinition level](https://en.bem.info/tools/bem/bem-tools/levels/). + + + +### 2. Create a block + +To provide correct work to all object on the page, it is necessary to specify additional functionality of `hello` block on your redefinition level. + +1. Create a directory of `hello` block on `desktop.blocks` level. +2. Create [the implementation technology files](https://bem.info/method/filesystem/) (`CSS`, `JS`, `BEMHTML`) required to the block in **hello** directory. + A block directory name and its nested files must coincide with block name specified in a BEMJSON file. + + * `hello.js` – describes dynamic page functionality + * `hello.bemhtml` – a template for generation of the block HTML representation + * `hello.css` – changes a custom design on the page + + + +### 3. Implement `hello` block + +To implement the block in BEM terms, use the created technology files. + + + +#### 3.1 Implement `hello` block in JavaScript technology + +1. Describe a block reaction depending on a user action using `onSetMod` property in the `desktop.blocks/hello/hello.js` file. A click on the button adds the user name from the input field into the greeting phrase. +JavaScript code is written using [i-bem.js](https://ru.bem.info/technology/i-bem/) (this article is available only in russian language) declarative JavaScript framework. + + ```js + onSetMod: { + 'js': { + 'inited': function() { + this._input = this.findBlockInside('input'); + + this.bindTo('submit', function(e) { + e.preventDefault(); + this.elem('greeting').text('Hello, ' + this._input.getVal() + '!'); + }); + } + } + } + + ``` + +2. To represent current JavaScript code, use [YModules](https://bem.info/tools/bem/modules/) modular system . + + ```js + modules.define( + 'hello', // a block name + ['i-bem__dom'], // dependence connection + function(provide, BEMDOM) { // a function that received names of the used modules + provide(BEMDOM.decl('hello', { // a block declaration + onSetMod: { // a constructor that describes reaction on an event + 'js': { + 'inited': function() { + this._input = this.findBlockInside('input'); + + this.bindTo('submit', function(e) { // the event that causes reaction + e.preventDefault(); // prevention of event work by default (form data sending to the server with page reload) + this.elem('greeting').text('Hello, ' + this._input.getVal() + '!'); + }); + } + } + } + })); + }); + ``` + + + +#### 3.2 Implement `hello` block in BEMHTML technology + +[BEMHTML](https://bem.info/technology/bemhtml/current/rationale/) – technology that processes BEMJSON declaration to create HTML layout of a web page. + +1. Write [BEMHTML tempate](https://bem.info/technology/bemhtml/current/reference/) and specify that `hello` block has JavaScript implementation. +2. Implement `hello` block with form, adding `tag` mode. + +```js +block('hello')( + js()(true), + tag()('form') +); +``` + + + +#### 3.3 Implement `hello` block in CSS technology + +Create your own CSS rules for `hello` block. For example: + +```js +.hello +{ + color: green; + padding: 10%; +} + +.hello__greeting +{ + margin-bottom: 12px; +} + +.hello__input +{ + margin-right: 12px; +} +``` +To change the position of the block on the page and leave it in its original form in the library, mix element using the method `mix` in the input data (BEMJSON). + +```js +{ + block: 'input', + mods: { theme: 'islands', size: 'm' }, + mix: { block: 'hello', elem: 'input' }, // mix element to add CSS rules + name: 'name', + placeholder: 'User name' +} +``` +[Code sample](https://gist.github.com/4exova/683b6da16aa7aa0399f3) hello.bemjson.js. + + + +## The final result + +To see the result of the project, please refresh the page: + + http://localhost:8080/desktop.bundles/hello/hello.html + +Since the project consists only of one page, in full build was no need. Description of a more complex project is in [Starting your own project](https://bem.info/tutorials/start-with-project-stub/) article. diff --git a/QuickStart.md b/QuickStart.md index 919a4a2..033bb7d 100644 --- a/QuickStart.md +++ b/QuickStart.md @@ -1,264 +1,276 @@ -# Как создать динамическую страницу с БЭМ +## Быстрый старт по созданию статической страницы с БЭМ -В этой статье мы рассмотрим пример реализации динамической функциональности страницы по [БЭМ-методологии](http://ru.bem.info/method/). +В этой статье рассмотрен пример реализации статической страницы по [БЭМ-методологии](https://ru.bem.info/method/). -# Что должно получиться +## Что должно получиться -Итогом проделанной работы будет страница с приветствием пользователя. Страница будет состоять из поля ввода, кнопки и приветствия. После того, как пользователь введет имя в поле и нажмет кнопку, его имя автоматически подставится в приветствие. +Страница приветствия пользователя, содержащая поле ввода, кнопку и текст. При нажатии на кнопку страница обновляется и текст дополняется значением, введенным в поле. -# Установка +![страница приветствия](https://img-fotki.yandex.ru/get/15561/289488726.0/0_21856b_45166628_orig) -**Требования к установке** +## С чего начать -Для начала работы с любым БЭМ-проектом нужен [Node.js](http://nodejs.org). +### Минимальные требования -Устанавливаем свой собственный БЭМ-проект. В этом нам поможет [шаблонный репозиторий](https://github.com/bem/project-stub), который содержит необходимый минимум конфигурационных файлов и папок. Делаем локальную копию `project-stub`. +Установленная платформа [Node.js 0.10](http://nodejs.org). - git clone https://github.com/bem/project-stub.git start-project - cd start-project - npm install +### Локальная копия и настройка окружения -Собираем проект с помощью [ENB](http://enb-make.info/): +Для быстрого и простого создания БЭМ-проекта потребуется [шаблонный репозиторий](https://github.com/bem/project-stub), содержащий необходимый минимум конфигурационных файлов и папок. - node_modules/.bin/enb make +1. Сделайте локальную копию `project-stub`. -Запускаем сервер: + **NB** В данном документе описана процедура установки для ревизии [13ae0e18ef8f48bc552b4944f7e5971c5b5f4768](https://github.com/bem/project-stub/ commit/13ae0e18ef8f48bc552b4944f7e5971c5b5f4768). Процесс установки последующих версий может отличаться. - node_modules/.bin/enb server + ```bash + git clone https://github.com/bem/project-stub.git start-project + cd start-project + git checkout 13ae0e18ef8f48bc552b4944f7e5971c5b5f4768 + npm install + ``` -При изменении конфигурации проекта нужно перезапускать сервер. Текущий процесс прерывается (`Ctrl+C`) и снова возобновляется командой запуска. +2. Запустите сервер с помощью [ENB](https://ru.bem.info/tools/bem/enb-bem-techs/): -Открываем браузер, чтобы проверить запустился ли сервер на компьютере: + ```bash + node_modules/.bin/npm start + ``` - http://localhost:8080/desktop.bundles/index/index.html +3. Проверьте результат по ссылке [http://localhost:8080/desktop.bundles/index/index.html](http://localhost:8080/desktop.bundles/index/index.html). -По умолчанию эта страница содержит примеры блоков библиотеки `bem-components`. + Должна открыться страница с примерами блоков библиотеки: -Альтернативный вариант для сборки проекта –– [bem-tools](http://ru.bem.info/tools/bem/bem-tools/). Результаты сборки в обоих случаях одинаковы. + ![главная страница](https://img-fotki.yandex.ru/get/15493/289488726.0/0_218be7_cbbd5b69_orig) -Про сборку проекта при помощи `bem-tools` вы можете почитать, пройдя по это ссылке http://ru.bem.info/tools/bem/bem-tools/commands/#bem-make. +## Пошаговая инструкция по созданию проекта -# Пошаговая инструкция по созданию проекта +Процедура разработки страницы приветствия состоит из следующих этапов: -Этот раздел содержит пошаговую информацию по созданию динамической страницы. +1. [Создание страницы](#page_creation) + 1.1 [Описание страницы в BEMJSON-файле](#BEMJSON_declaration) +2. [Создание блока](#block_creation) +3. [Реализация блока hello](#block_hello_modification) + 3.1 [В технологии JavaScript](#JS_modification) + 3.2 [В технологии BEMHTML](#BEMHTML_modification) + 3.3 [В технологии CSS](#CSS_modification) -* [Создание страницы](#page_creation) –– рассмотрим варианты создания страницы. -** [Описание страницы в BEMJSON-файле](#BEMJSON_declaration) –– опишем страницу в БЭМ-терминах. -* [Создание блока](#block_creation) –– самостоятельно создадим блок. -** [Создание блока с файлом определенной технологии](#block_using_concrete_tech) –– рассмотрим возможность создавать файлы блока конкретных технологий. -* [Переопределение блока `hello`](#block_hello_modification) –– внесем необходимые изменения в файлы технологий блока. -** [Реализация блока в технологии JS](#JS_modification) –– реализуем блок в технологии JavaScript. -** [Реализация блока в технологии BEMHTML](#BEMHTML_modification) –– реализуем блок в технологии BEMHTML. -** [Реализация блока в технологии CSS](#CSS_modification) –– реализуем блок в технологии CSS. -* [Сборка проекта](#build) –– запустим сборку проекта. +После выполнения всех шагов можно смотреть [результат](#result). -## Создание страницы +### 1. Создание страницы -Макеты страниц размещаются в каталоге `desktop.bundles`. Данный каталог содержит одну директорию –– `index`. Вы можете продолжать работу с этой директорией. Для этого необходимо заменить декларацию файла `index.bemjson.js`. Пример описания BEMJSON-файла мы рассмотрим ниже. +Исходники страниц размещаются в каталоге `start-project/desktop.bundles`. Изначально в проекте присутствует главная страница `index.html` с примерами блоков библиотеки [bem-components](https://ru.bem.info/libs/bem-components/). -Альтернативный вариант –– создание новой страницы, используя команду [bem-tools](http://ru.bem.info/tools/bem/bem-tools/): +Для начала работы с собственным проектом создайте новую страницу. Разместите в `desktop.bundles` каталог с именем `hello` и добавьте в него файл `hello.bemjson.js`. - bem create -l desktop.bundles -b hello - -* `-l desktop.bundles` –– указывает на уровень переопределения `desktop.bundles`; -* `-b hello` –– определяет имя блока страницы, в нашем случае `hello`. - -Выбирайте удобный для вас вариант. Дальше мы продолжим создание проекта на основе страницы `hello`. -### Описание страницы в BEMJSON-файле - -#### Создаем свой блок - -Первым делом нам нужно добавить на страницу блок приветствия. Для того, чтобы разместить его на странице, добавим блок **hello** в файл `desktop.bundles/hello/hello.bemjson.js`. - -{ block: 'hello' } - -Дальше внутрь блока **hello** поместим элемент **greeting** с приветствием пользователя: - -``` -{ - elem: 'greeting', - content: 'Привет, %пользователь%!' -} -``` - -#### Используем готовые блоки - -Кроме приветствия на странице должно быть поле ввода и кнопка. Блоки **input** и **button** мы берем готовые из библиотеки [bem-components](http://ru.bem.info/libs/bem-components/v2/). И вкладываем их в элемент **greeting**. - -``` -{ - elem: 'greeting', - content: 'Привет, %пользователь%!' - }, - { - block: 'input', - mods: {theme: 'islands', size: 'm'}, - placeholder: 'Имя пользователя' - }, - { - block : 'button', - text : 'Нажать', - mods : { theme : 'islands', size : 'm' } - } -} -``` - -Если вы хотите внести какие-либо изменения в готовые блоки, это можно сделать на своем уровне переопределения. Подробнее об этом можно почитать, пройдя по ссылке http://ru.bem.info/tools/bem/bem-tools/levels/. +#### 1.1 Описание страницы в BEMJSON-файле + +[BEMJSON-файл](https://ru.bem.info/technology/bemjson/) – это структура страницы, описанная в терминах блоков, элементов и модификаторов. + +1. Добавьте на своем проекте описание блока `hello` в файле `desktop.bundles/hello/hello.bemjson.js`. + Блок **hello** – это сущность, которая содержит в себе все необходимые для проекта элементы. + + ```js + { + block: 'page', + title: 'hello', + head: [ + { elem: 'css', url: '_hello.css' } + ], + scripts: [{ elem: 'js', url: '_hello.js' }], + mods: { theme: 'islands' } + content: [ + { + block: 'hello' + } + ] + } + ``` -Все необходимые блоки добавлены. Так будет выглядеть полный код страницы `desktop.bundles/hello/hello.bemjson.js`: +2. Поместите элемент `greeting` с текстом приветствия пользователя (поле **content**) в блок **hello**. + Элемент **greeting** – это подсущность, в которую вкладывается фраза приветствия и готовые реализации блоков. -``` -({ - block: 'page', - title: 'hello', - head: [ - { elem: 'css', url: '_hello.css' } - ], - scripts: [{ elem: 'js', url: '_hello.js' }], + ```js content: [ - { - block: 'content', - content: [ - { - block: 'hello', - name: 'BEMHTML', - content: [ - { - elem: 'greeting', - content: 'Привет, %пользователь%!' - }, { - block: 'input', - mods: {theme: 'islands', size: 'm'}, - placeholder: 'Имя пользователя' - }, { - block : 'button', - text : 'Нажать', - mods : { theme : 'islands', size : 'm' } - } - ] - } - ] - } - ] -}) -``` + { + block: 'hello', + content: [ + { + elem: 'greeting', + content: 'Привет, %пользователь%!' + } + ] + } + ] + ``` + +3. Чтобы создать поле ввода и кнопку возьмите готовые реализации блоков `input` и `button` из библиотеки `bem-components` и добавьте их в элемент `greeting`. + + ```js + ({ + block: 'page', + title: 'hello', + head: [ + { elem: 'css', url: '_hello.css' } + ], + scripts: [{ elem: 'js', url: '_hello.js' }], + mods: { theme: 'islands' }, + content: [ + { + block: 'hello', + content: [ + { + elem: 'greeting', + content: 'Привет, %пользователь%!' + }, + { + block: 'input', + mods: { theme: 'islands', size: 'm' }, + name: 'name', + placeholder: 'Имя пользователя' + }, + { + block : 'button', + mods : { theme : 'islands', size : 'm', type : 'submit' }, + text : 'Нажать' + } + ] + } + ] + }) + ``` -Чтобы проверить запустился ли файл, откройте браузер по адресу: +Чтобы убедиться, что страница отображает все необходимые объекты, откройте [http://localhost:8080/desktop.bundles/hello/hello.html](http://localhost:8080/desktop.bundles/hello/hello.html). - http://localhost:8080/desktop.bundles/hello/hello.html +Если вы хотите внести какие-либо изменения в существующие блоки, это можно сделать на своем [уровне переопределения](https://ru.bem.info/tools/bem/bem-tools/levels/). -## Создание блока - -На уровне `desktop.blocks` создаем директорию блока **hello**. По умолчанию блок будет представлен набором файлов для всех технологий реализации (`CSS/STYL`, `JS`, `BEMHTML`). - - bem create -l desktop.blocks -b hello - -* `-l desktop.blocks` –– указывает на уровень переопределения `desktop.blocks`; -* `-b hello` –– задает имя директории блока, в нашем случае `hello`. +### 2. Создание блока -Другой способ –– создание блока вручную. Для этого на уровне `desktop.blocks` создадим папку **hello** и разместим в ней необходимые для проекта файлы технологий реализации блока. +Чтобы элементы на странице работали должным образом необходимо прописать дополнительную функциональность блока `hello` на своем уровне переопределения. - +1. Создайте вручную каталог блока `hello` на уровне `desktop.blocks`. +2. Разместите в нем необходимые для проекта [файлы технологий реализации блока](https://ru.bem.info/method/filesystem/) (`CSS`, `JS`, `BEMHTML`). Название каталога блока и вложенных в него файлов должны совпадать с именем блока, которое прописано в BEMJSON-файле. -### Создание блока с файлом определенной технологии - -Блок можно создавать с файлом определенной технологии. Более подробную информацию об этом можно найти в командах [bem-tools](http://ru.bem.info/tools/bem/bem-tools/commands/#Создание-блока-в-определённой-технологии). + * `hello.js` – описывает динамическую функциональность страниц; + * `hello.bemhtml` – шаблоны для генерации HTML-представления блока; + * `hello.css` – изменяет внешний вид объектов на странице. -## Переопределение блока `hello` -Чтобы наш проект заработал должным образом, нужно переопределить файлы технологий реализации. +### 3. Реализация блока hello + +Для представления блока в терминах БЭМ необходимо описать его в файлах технологий реализации. -### Реализация блока в технологии JS +#### 3.1 Реализация блока в технологии JavaScript -В файле `desktop.blocks/hello/hello.js` описываем реакцию блока на выполнение действия, в нашем случае нажатие кнопки, с помощью специального свойства `onSetMode`. При нажатии кнопки в приветствие будет автоматически подставляться имя пользователя, введенное в поле **input**. +1. Опишие в файле `desktop.blocks/hello/hello.js` реакцию блока на действие пользователя с помощью специального свойства `onSetMode`. При нажатии кнопки в текст приветствия будет подставляться имя пользователя, введенное в поле input. + JavaScript-код написан с использованием декларативного JavaScript-фреймворка – [i-bem.js](https://ru.bem.info/technology/i-bem/). -``` -onSetMod: { - 'js': { - 'inited': function() { - this._input = this.findBlockInside('input'); - this._button = this.findBlockInside('button'); - - this._button.on('click', function() { - this.elem('greeting').text('Hello, ' + this._input.getVal() + '!'); - }, this); + ```js + onSetMod: { + 'js': { + 'inited': function() { + this._input = this.findBlockInside('input'); + + this.bindTo('submit', function(e) { + e.preventDefault(); + this.elem('greeting').text('Привет, ' + this._input.getVal() + '!'); + }); + } } } -} - -``` -Данный JavaScript заворачиваем в [модульную систему YModules](http://ru.bem.info/tools/bem/modules/): -``` -modules.define( - 'hello', - ['i-bem__dom'], - function(provide, BEMDOM) { - provide(BEMDOM.decl('hello', { - onSetMod: { - 'js': { - 'inited': function() { - this._input = this.findBlockInside('input'); - this._button = this.findBlockInside('button'); - - this._button.on('click', function() { - this.elem('greeting').text('Hello, ' + this._input.getVal() + '!'); - }, this); + ``` + +2. Используйте модульную систему [YModules](https://ru.bem.info/tools/bem/modules/), чтобы представить данный JavaScript-код: + + ```js + modules.define( + 'hello', // имя блока + ['i-bem__dom'], // подключение зависимости + function(provide, BEMDOM) { // функция, в которую передаются имена используемых модулей + provide(BEMDOM.decl('hello', { // декларация блока + onSetMod: { // конструктор для описания реакции на события + 'js': { + 'inited': function() { + this._input = this.findBlockInside('input'); + + this.bindTo('submit', function(e) { // событие, на которое будет реакция + e.preventDefault(); // предотвращение работы события по умолчанию (отправка данных формы на сервер с перезагрузкой страницы) + this.elem('greeting').text('Привет, ' + this._input.getVal() + '!'); + }); + } } } - } - })); - }); -``` + })); + }); + ``` -### Реализация блока в технологии BEMHTML +#### 3.2 Реализация блока в технологии BEMHTML -Для того, чтобы наш JavaScript применился пишем BEMHTML-шаблон, в котором указываем, что наш блок **hello** имеет JavaScript-реализацию: +[BEMHTML](https://ru.bem.info/technology/bemhtml/current/rationale/) – технология, которая преобразует входные данные из BEMJSON-файла в HTML. -``` -block hello, js: true +1. Напишите [BEMHTML-шаблон](https://ru.bem.info/technology/bemhtml/current/reference/) и укажите в нем, что блок `hello` имеет JavaScript-реализацию. +2. Оберните блок `hello` в форму, добавив моду `tag`. + +```js +block('hello')( + js()(true), + tag()('form') +); ``` -### Реализация блока в технологии CSS +#### 3.3 Реализация блока в технологии CSS -Для блока **hello** создаем свои CSS-правила. К примеру, такие: +Для блока `hello` создайте свои CSS-правила. Например, такие: -``` +```js .hello - color: green -``` - - -## Сборка проекта - -При обновлении страницы сервер пересобирал только ту часть проекта, которую затронули наши изменения. Для сборки всего проекта целиком воспользуемся командой `ENB`: +{ + color: green; + padding: 10%; +} - $ node_modules/.bin/enb make +.hello__greeting +{ + margin-bottom: 12px; +} -# Результат +.hello__input +{ + margin-right: 12px; +} +``` +Чтобы изменить положение блока на странице используйте метод и при этом оставить его в первоначальном виде в библиотеке, подмешайте элемент с помощью метода `mix` во входных данных (BEMJSON). -Обновляем страницу в браузере с адресом +```js +{ + block: 'input', + mods: { theme: 'islands', size: 'm' }, + mix: { block: 'hello', elem: 'input' }, // подмешиваем элемент для добавления CSS-правил + name: 'name', + placeholder: 'Имя пользователя' +} +``` +[Полный код](https://gist.github.com/4exova/981a36cedceffa472742) BEMJSON-файла. - http://localhost:8080/desktop.bundles/hello/hello.html + -и видим страницу приветствия: +## Результат -*скрин* +Чтобы увидеть итог проделанной работы обновите страницу: -Заполняем поле ввода любым именем, например, Вася, нажимаем кнопку и получаем результат: + http://localhost:8080/desktop.bundles/hello/hello.html -*скрин* +Поскольку проект состоял всего из одной страницы, то необходимость в полной сборке отсутствует. Информация о том, как написать более сложный проект приведена в статье [Создаем свой проект на БЭМ](https://ru.bem.info/tutorials/start-with-project-stub/). diff --git a/RationaleForJS.md b/RationaleForJS.md new file mode 100644 index 0000000..853dd70 --- /dev/null +++ b/RationaleForJS.md @@ -0,0 +1,315 @@ +## БЭМ для JavaScript + +В разработке интерфейсов важно помнить, что сайт – это растущий организм. +Ситуации, когда в коде сайта нет определенной структуры и фиксированных правил написания, приводят к сложностям в процессе разработки и поддержки. Чтобы обеспечить долгую и безоблачную жизнь вашему проекту следует начать с общего подхода, с методологии. + +### Зачем в JavaScript компонентный подход + +Те времена, когда веб-сайты состояли из статического контента и нескольких скриптов для обработки, остались позади. + +Современные пользователи становятся все требовательнее: веб должен быть быстрыми, динамическим, удобным, интерактивным и уметь адаптироваться под запросы потребителя. Сайты уже не представляют собой несколько страниц текста с картинками и ссылками; сейчас они обрабатывают информацию и решают многие задачи. Возрастание роли веб-приложений очевидны – они не требуют установки у пользователя и их гораздо проще настраивать под этого самого пользователя. Программами «из коробки» теперь все чаще можно воспользоваться непосредственно в вашем любимом браузере. +Разработка становится все сложнее и интереснее: сайты увеличиваются в объемах, растет количество постоянных пользователей, владельцы сайта хотят угодить всем, так как напрямую от этого зависит их прибыль, повышается конкуренция. Сайт должен быть очень мобильным и уметь реагировать на все изменения окружающей среды практически мгновенно. А что же в таком случае остается делать разработчику? Ответ один: чтобы выжить, ему необходимо учиться оптимизировать разработку, умело пользоваться всем своим кодом и быстро отыскивать проблемные места, устраняя ошибку локально, не затрагивая никакие другие части кода. + +Как все это воплотить в жизнь? Типичный человеческий подход к преодолению сложной проблемы — дробление ее на более простые части. Идея разделения на компоненты не нова. Она в полном объеме реализована в ООП. Нам остается только перенять этот богатый опыт. + +Будущее (кажется, что это уже настоящее) веб-приложений – за переходом на компонентную структуру. + +Компонентный подход в JavaScript позволяет объединять сущности по общему признаку и организовывать их в соответствии с определенными правилами и ограничениями. Не имеет значения, как этот подход реализован, потому что у каждого компонента есть свои методы, которые знают все о себе. [Общение с внешними блоками](#independent-blocks) происходит либо через родителя, либо через каких-то посредников. + +Компонентная структура обеспечивает гибкость контроля версий и помогает избежать конфликтов во время ведения параллельной разработки. Перенос логики, связанной с конкретными блоками, в отдельные файлы, улучшает читаемость кода и ускоряет процесс создания и корректировки проекта. Именно эту задачу решает БЭМ. + +## Применение методологии БЭМ к JavaScript + +В процессе эволюции технологий написания сайтов появился БЭМ. Суть данного подхода – разбиение страницы на блоки и элементы. Определение свойств, их значений и дополнительного функционала блоков и элементов выполняется с помощью модификаторов. Еще одно ключевое понятие БЭМа – [уровни переопределения](https://ru.bem.info/tools/bem/bem-tools/levels/). Они позволяют расширять и дополнять поведение одного и того же блока. + +Изначально перед разработчиками ставились задачи отображения внешнего вида страницы, поэтому методология БЭМ применялась больше для именования классов в CSS. Как и CSS JavaScript пишется к каждому блоку отдельно и располагается непосредственно в самом блоке. Блок становится независимым и в функциональном плане. JavaScript приводит в действие какие-то модификаторы и это те самые модификаторы, которые приводят в действие какие-то CSS свойства. Они напрямую связаны и разделять их нет смысла, поскольку JavaScript и CSS оперирует одними терминами. + +Как же применить БЭМ-методологию к JavaScript? БЭМ вводит единую семантику на всех уровнях (HTML, CSS, JavaScript, шаблоны, дизайн интерфейсов) и предоставляет единый гибкий API поверх разнообразного набора методов работы с DOM. А на уровне файловой системы все про одну сущность складывает в одну папку, предназначенную для повторного использования и расширения. + +Чтобы на деле понять как работает подход БЭМ, понадобиться разобраться в следующих определениях, особенностях подхода и принципах: + +* [декларативный подход](#declaration) +* [взаимодействие блоков](#independent-blocks) +* [модификатор](#modifier) +* [метод](#method) +* [событие](#event) +* [изменение поведения блока](#customization) +* [инициализация](#initialization) + + + + +### Декларативный подход + +Важной особенностью БЭМ технологии является декларативный принцип. Подобно работе декларативных языков программирования, JavaScript-код содержит не последовательный алгоритм работы блока, а набор действий и условий, при которых эти действия необходимо выполнять. + +Декларативность проявляется в объявлении того, к каким блокам или их модификациям применим код компонента. При декларировании какой-то сущности известно, что она имеет определенные состояния и при переходе в эти состояния с ней происходят конкретные действия, а при возвращении к предыдущему состоянию с ней случаются обратные действия. + +<Пример> + +<Расшифровка примера> + + + +### Способы взаимодействия блоков + +Блок в БЭМ – это независимый компонент, который можно переместить в любое место на странице, в том числе и в другой блок или же на другой проект. Блок может поддерживать разные технологии – HTML, CSS, JavaScript и т.п. БЭМ-методолгия позволяет на уровне проекта изменить внешний вид или поведение существующего блока, добавить новые блоки. Однако, несмотря на независимость блоков, на уровне JavaScript они обязаны общаться друг с другом. + +### Написание JavaScript-кода с сохранением независимости блоков + +Простой пример поможет понять как происходит взаимодействие блоков. + +**Описание** + +Есть форма, перед отправкой которой необходимо проверить, что введено корректное значение, и в случае ошибки показать попап с предупреждением. + +Выглядит это следующим образом: + +```html +
+ + + +
+``` + +```css +.popup { + display: none; +} + +.popup_visible { + display: block; +} +``` +Чтобы описанная конструкция заработала необходимо написать JavaScript-код. + +### Реализация в старом стиле + +Приведенный пример показывает, как делать **не надо**. + +```js +$('.button').on('click', function(e) { + if (!/\S+@\S+\.\S+/.test($('.input').val())) { + $('.popup').addClass('popup_visible'); + return false; + } +}); +``` +Согласно представленному коду, кнопка «знает» про поле ввода и попап, кроме того явно предполагается, что она находится внутри формы. + +Однако реальность такова, что проекты не стоят на месте, они развиваются. Приходит момент, когда необходимо что-то добавить, переместить или изменить. Процесс реорганизации внутренней структуры в представленном коде, будь то удаление одного из компонентов или появление новых элементов, приведет к его поломке. При возможном переиспользовании такой кнопки, обязательно придется применить все компоненты с такими же классами и гарантировать, что больше нигде на странице они не встретятся. + +**Результат**
+Данный код сложно и поддерживать, и нерационально реиспользовать, если только не делать точную копию проекта. + +#### Улучшенная реализация + +```js +$('.form').on('submit', function(e) { + if (/\S+@\S+\.\S+/.test($('.input', this).val())) return true; + e.preventDefault(); + $('.popup', this).addClass('popup_visible'); +}); +``` +**Изменения**
+Согласно новому коду, форма, за все что происходит с ней, отвечает сама. Теперь компоненты внутри ничего не знают о существовании друг друга. При необходимости можно взять кнопку и перенести ее на другой проект, поскольку она стала независимой. В этом случае кнопка не будет нести в себе знание о какой-то форме, поле ввода и попапе. + +**Результат**
+Все селекторы вынесены за рамки контекста формы и теперь можно добавлять любое количество новых полей ввода, попапов и кнопок за пределами формы – ничего не сломается.
+Но, если добавить еще одно поле, придется реорганизовывать код. Кроме того, чтобы гарантировать перекрытие попапом любых других элементов на странице, необходимо положить его в самом конце DOM-дерева, перед закрывающим тегом ``. + +#### Миксы + +**Изменения**
+Решить задачу с добавлением ещё одного поля можно при помощи миксов. Микс — это объединение нескольких блоков на одном DOM-узле.
+Попап вынесен из формы и к нему добавлено еще одно поле. А сами поля смиксованы с элементами формы. + + +```html +
+ + + +
+ +``` +Теперь код выглядит так: + +```js +$('.form').on('submit', function(e) { + if (/\S+@\S+\.\S+/.test($('.form__email', this).val())) return true; + e.preventDefault(); + $('.form__hint').addClass('popup_visible'); +}); +``` +**Результат**
+Исправлены предыдущие проблемы, но появилась новая: если на странице окажется несколько форм, как каждая из них найдет свой попап? + +В качестве решений этой проблемы представлено несколько вариантов: + +* [Один блок на нескольких DOM-узлах](#distrib_block) +* [Использование посредника](#mediator) + + + +#### Один блок на нескольких DOM-узлах + +**Изменения**
+В этом случае реализован механизм, который позволит выражать один блок на нескольких DOM-узлах. Схематично он может выглядеть так: + +```html +
+ + + +
+ +``` +Форме добавлен data-атрибут с идентификатором и помимо элемента к попапу примиксована сама форма с таким же идентификатором. +Теперь в коде можно указать, что необходим элемент `hint` именно этого блока `form`, а не какого-то другого: + +```js +$('.form').on('submit', function(e) { + if (/\S+@\S+\.\S+/.test($('.form__email', this).val())) return true; + e.preventDefault(); + $('.form__hint').filter('.form[data-id=' + $(this).data('id') + ']').addClass('popup_visible'); +}); +``` +**Результат**
+Теперь через конкретный data-атрибут можно найти нужный элемент. + + + +#### Использование посредника + +Следующее решение позволяет сохранить независимость блоков, но избавиться от необходимости вносить изменения в DOM. +Для этого необходимо воспользоваться паттерном проектирования [Посредник](https://ru.wikipedia.org/wiki/Посредник_%28шаблон_проектирования%29). + +Паттерн обеспечит взаимодействие компонентов таким образом, что они ничего не будут знать друг о друге, но будут знать о существованиии посредника. Вся коммуникация происходит на основе сообщений, которые компоненты публикуют и слушают на посреднике. + +**Изменения**
+В качестве самого простого примера посредником может выступить `body`. Он всегда присутствует в коде и знает о всех компонентах, которые находятся внутри, к тому же может обеспечить обмен сообщениями. + +```html + +
+ + + +
+ + +``` +Код выглядит так: + +```js +var page = $('.page'); + +page.on('error', function(e, data) { + $('.popup') + .text(data) + .addClass('popup_visible'); +}); + +$('.form').on('submit', function(e) { + if (/\S+@\S+\.\S+/.test($('.form__email', this).val())) return true; + e.preventDefault(); + page.trigger('error', 'Ошибка валидации'); +}); +``` +**Результат**
+В случае ошибки валидации форма сообщает об этом посреднику — `page`. Все компоненты, которые должны реагировать на это событие, могут «подписаться» на него через `page.on()`. + + + +### Модификаторы + +Согласно БЭМ-методологии, состояние блока и его элементов описывается модификаторами. Модификатор задает блоку определенное состояние. Каждому блоку можно присвоить один или несколько модификаторов (у блока также может не быть модификаторов вообще). У модификатора есть имя и значение. Любой перевод блока в другое состояние должен производиться при помощи установки модификатора. + +Каждому блоку можно установить один или несколько модификаторов. Блок может не иметь модификаторов. Список допустимых модификаторов и их значений определяет разработчик блока. + +Согласно БЭМ-модификаторы могут быть не только у блоков, но и у элементов. Используемые для этого методы похожи. + +Простой модификатор — частный случай, когда важно только наличие или отсутствие данного модификатора у блока, а его значение несущественно. Например, модификатор описывающий состояние «отключен»: disabled + +#### Управление модификаторами + +Модификаторы могут добавляться, удаляться и менять значение. + +#### Установка триггеров + +Триггеры, выполняемые при установке модификаторов, описываются в декларации блока. + +В качестве параметров триггерам передаются: + +* имя модификатора; +* выставляемое значение модификатора. + +```js +{ + 'mod1': function(modName, modVal, prevModVal) { /* ... */ }, // установка mod1 в любое значение + 'mod2': { + 'val1': function(modName, modVal, prevModVal) { /* ... */ }, // триггер на установку mod2 в значение val1 + 'val2': function(modName, modVal, prevModVal) { /* ... */ }, // триггер на установку mod2 в значение val2 + '': function(modName, modVal, prevModVal) { /* ... */ } // триггер на удаление модификатора mod2 + 'mod3': { + 'true': function(modName, modVal, prevModVal) { /* ... */ }, // триггер на установку простого модификатора mod3 + '': function(modName, modVal, prevModVal) { /* ... */ }, // триггер на удаление простого модификатора mod3 + }, + '*': function(modName, modVal, prevModVal) { /* ... */ } // триггер на установку любого модификатора в любое значение +} +``` + + + +### Методы + +Чтобы динамически изменять состояния блоков и элементов, есть специальные методы для установки и снятия модификаторов. В коде компонента можно записать, как блок или элемент должен отреагировать на изменение модификатора. Эта запись тоже декларативна. Например, какой-то блок при установке модификатора disabled скрывает показанный попап. + +Кроме реакции на модификаторы, в блоке могут быть определены его собственные методы. Определенные в блоке методы могут быть вызваны им самим или другими блоками. + +Например, как выглядит какой-то метод какого-то блока. + +Любой метод блока (в том числе и методы обработки модификаторов) может быть переопределен. Подробнее об этом в пункте [Изменение поведения блока](#customization). + +<Пример> + +<Расшифровка примера> + + + +### События + +События играют важную роль в JavaScript. Специальные методы позволяют работать с событиями как на DOM-узлах, соответствующих блокам, так и на BEM-объектах (JavaScript-объектах, представляющих экземляры блоков). + +<Пример> + +<Расшифровка примера> + + + +### Изменение поведения блоков + +Можно переопределять и доопределять методы блока и функции реакции на изменения модификаторов. + +#### Переопределение поведения + +#### Расширение поведения + + + +### Инициализация + +Работа блока начинается с его инициализации. В этот момент у блока появляется модификатор js_inited. +Многим блокам нет необходимости делать сразу же полную инициализацию. Инициализация может происходить только на ключевые события для этого блока, например, клик по элементу этого блока. + +## Подведем итоги + +В наше время значение веб-приложений возростает с каждым днем, появляются новые и растут в объеме старые сайты. Повышение запросов к качеству и скорости выполнения проектов приводит к поиску новых технологий, которые облегчат разрабоку. БЭМ обеспечит эффективное задействование имеющегося кода и продление существования проекта. Ключевые преимущества в использовании БЭМ-методологии: + +* **расширяемость и быстрая разработка.** Связывая на уровне кода CSS и JS в одних терминах, складывая все рядом на уровне файловой системы, вы получаете независимые компоненты, которые знают все о себе и их легко можно переносить между проектами. +* **оптимизация процесса.** Декларативность позволяет сохранить с одной стороны независимость компонентов, а с другой стороны позволяет повлиять на них, в том числе не только из CSS, но и из JavaScript, и в каждом конкретном случае добавить новую функцинальность, не ломая базовую. +* **высокая готовность к частым изменениям** + +Теперь вы можете оперировать принципами БЭМ при написании JavaScript-кода. Чтобы ознакомиться со специализированным JavaScript-фреймворком, который разработан по БЭМ-методологии читайте статью [i-bem.js: руководство пользователя](https://ru.bem.info/technology/i-bem/current/i-bem-js/).