## Вступ

### Коротко о методологіях CSS

При розробці проектів нам часто доводиться створювати компоненти, які схожі один на одного, але при використанні в різних місцях мають різний зовнішній вигляд або невеликі модифікації. Для цього розробники часто використовують поширені методології верстки, наприклад БЕМ, згідно з якою кожен блок (в нашому випадку компонент) має свої модифікації, які додаються новим класом з таким же ім'ям і додатковою назвою модифікатора. Більш наочно це продемонстровано на прикладі нижче.

<vuep template="#simpledemo"></vuep>
<script v-pre type="text/x-template" id="simpledemo">
<template>
  <div class="good">
    <header class="good__header">Header</header>
    <div class="good__strip"></div>
    <div class="good__body">Гарний компонент</div>
    <div class="good__button">+</div>
  </div>
</template>

<style>
.good {
  position: relative;
  width: 100%;
  min-height: 200px;
  background-color: #e0e0e0;
  border-radius: 15px;
}

.good__header {
  width: 100%;
  height: 40px;
  background-color: #bf360c;
  border-radius: 15px 15px 0 0;
  color: #fff;
  font-weight: bold;
  text-align: center;
  line-height: 40px;
}

.good__strip {
  width: 100%;
  height: 5px;
  background-color: #870000;
}

.good__body {
  padding: 30px;
  font-weight: bold;
  font-size: 30px;
  text-align: center;
}

.good__button {
  position: absolute;
  bottom: -25px;
  left: calc(50% - 25px);
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background-color: #795548;
  color: #fff;
  font-weight: bold;
  font-size: 40px;
  text-align: center;
  line-height: 50px;
}

.good__button:hover {
  cursor: pointer;
  background-color: #4b2c20;
}
</style>
</script>

Нам потрібно використовувати цей компонент в іншому місці в іншій кольоровій схемі і без кнопки з плюсом. Згідно з методологією нам потрібно додати модифікатор до цього класу головного блоку, щоб не зламати оформлення самого блоку, а міняти тільки стилі його модифікації. На практиці це виглядає так:

> Додаємо клас з модфікатором cyan - `good_cyan`. Часто ви можете зустріти варіант, коли використовують `-` замість ` _`, а для позначення елемента блоку `--`, а не `__`. Але це вже нюанси. Так само прошу звернути вашу увагу, що гарним вибором найменування модифікаторів відповідно до їх належності до певної сторінки на якій він використовується або функціоналу, але не кольорового оформлення. У даному випадку використовувався модифікатор `cyan` для більшої наглядності.

<vuep template="#simpledemo2"></vuep>
<script v-pre type="text/x-template" id="simpledemo2">
<template>
  <div class="good good_cyan">
    <header class="good__header">Header</header>
    <div class="good__strip"></div>
    <div class="good__body">Гарний компонент</div>
    <div class="good__button">+</div>
  </div>
</template>

<style>
.good {
  position: relative;
  width: 100%;
  min-height: 200px;
  background-color: #e0e0e0;
  border-radius: 15px;
}

.good_cyan .good__header {
  background-color: #00bcd4;
  color: #000;
}

.good_cyan .good__strip {
  background-color: #008ba3;
  color: #000;
}

.good_cyan .good__button {
  display: none;
}

.good__header {
  width: 100%;
  height: 40px;
  background-color: #bf360c;
  border-radius: 15px 15px 0 0;
  color: #fff;
  font-weight: bold;
  text-align: center;
  line-height: 40px;
}

.good__strip {
  width: 100%;
  height: 5px;
  background-color: #870000;
}

.good__body {
  padding: 30px;
  font-weight: bold;
  font-size: 30px;
  text-align: center;
}

.good__button {
  position: absolute;
  bottom: -25px;
  left: calc(50% - 25px);
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background-color: #795548;
  color: #fff;
  font-weight: bold;
  font-size: 40px;
  text-align: center;
  line-height: 50px;
}

.good__button:hover {
  cursor: pointer;
  background-color: #4b2c20;
}
</style>
</script>

Ми використовували той же компонент, але вказали один клас з модифікатором і в стилях компонента просто додали стилі для даної модифікації цього блоку:

``` css
.good_cyan .good__header {
  background-color: #00bcd4;
  color: #000;
}

.good_cyan .good__strip {
  background-color: #008ba3;
  color: #000;
}

.good_cyan .good__button {
  display: none;
}
```

При використанні препроцесорів це буде виглядати ще гарніше і компактніше:

``` css
.good_cyan .good__header,
.good_cyan .good__strip
  background-color: #00bcd4
  color: #000

.good_cyan .good__button
  display: none
```

Тепер уявіть як добре контролювати оформлення певного блоку за допомогою таких модифікаторів. Ви просто описуєте потрібні вам стилі в іншому модификаторі і застосовуєте їх де потрібно, можна застосовувати різну кількість модифікаторів. Наприклад, в один і той же блок додати `.good_with-border` і `.good_red`. Так само хочу ще раз нагадати, що в основному блоки називають не відповідно до їх кольорового оформлення, а відповідно до їх належності (контекстом використання), наприклад, `.good_main-page` і `.good_article-page`. І з назви відразу стає зрозуміло, що цей блок з такими стилями використовується на головній сторінці, але такий же блок з модифікованими стилями використовується на сторінці статей. Більшість розробників використовують такий підхід і не шкодують про це. Одна з важливих переваг при даному підході - це можливість застерегти себе від непотрібних змін в основному блоці, міняти тільки його модифікації.

### Компоненти у вашому фреймворці

При компонентному підході така методика розробки виявляється дуже до речі і більш того стає дуже легкою для використання. Щоб використовувати компонент з іншими модифікаторами, ви звичайно повинні дозволити компоненту приймати ці модифікатори через вхідні властивості (props). У нашому прикладі, це буде виглядати приблизно так:

`MyComponent.vue <script>`
```js
  export default {
    props: {
      type: String
    }
  }
```

`MyComponent.vue <template>`
```html
<template>
  <div class="good" :class="mods && 'good_' + mods">
    <header class="good__header">Header</header>
    <div class="good__strip"></div>
    <div class="good__body">Good component</div>
    <div class="good__button">+</div>
  </div>
</template>
```

Тепер компонент може приймати строковий модифікатор `mods`, який він буде складати з основним класом компонента і вставляти його в атрибут class. І тепер ви можете спокійно використовувати ваш компонент в різних місцях, передаючи йому різні `mods` властивості. А стилі для них описуються вже в самому компоненті. Наприклад:

```js
// Використовуємо компонент з блакитною схемою кольорів
<MyComponent mods="cyan" />

// Використовуємо компонент зі схемою кольорів, яка призначена для сторінки "контакти"
<MyComponent mods="contacts" />
```

У самих стилях компонента ми просто додамо оформлення для блоку з модифікатором, тобто `.my-component-name_contacts`. Це легко і **ЯКЩО** ви не використовуєте у своїй верстці каскадів, то ваші модифікатори працюватимуть як очікується, не поламають інші елементи і основний блок.

> Під каскадами автор розуміє такий кейс: `div > .my-component-name > div:first-child` (це просто для прикладу, особливо часто можна зустріти коли така конструкція знаходиться навіть не в стилях самого блоку). Все буде працювати не як ви очікуєте, тому що в даному випадку порушується питання пріоритету застосування стилів і каскад в цьому випадку виграє. Так само найбільший пріоритет має `id` і `!important`. І якщо ви в якихось місцях вказали це, то не дивуйтеся. При вашому підході, вас уже нічого не врятує. В утопічному світі де все добре, мається на увазі що ви завжди дотримуєтесь методології. (Хочу зауважити, що це не казка і багато людей дійсно роблять все добре і потім дуже приємно підтримувати проект, який повністю написаний відповідно за таким підходом).

Але наш компонент написаний на даний момент не зовсім гнучкий. Щоб дати йому можливість приймати кілька модифікаторів тобто в якості параметра `mods` масив модифікаторів, а не просто рядок, то нам вже потрібно буде витягувати рядок додавання модифікаторів в компоненті в `computed properties` і обробляти там випадок якщо це масив і якщо це рядок. Насправді, це робиться дуже легко:

`Псевдокод`
```js
// Якщо це масив
if (mods is Array) {
  return mods.map(item => 'good' + '_' + item)
} else {
  return `good_${mods}`
}
```

Однак нам же потрібно ще перевірка на існування базового класу і можливість передавати різний префікс (багато хто використовує для позначення модифікаторів `-`, а не `_`). До того ж найголовніше, що якщо весь ваш проект використовує такий підхід, то було б не погано щоб ви не думали більше про це і щоб у вас завжди була можливість передавати модфікатори будь-яких блоків компонентів у вашому проекті. Якраз для цього вам відмінно зарадить плагін `vue-mods-names`, який дуже спрощує ваш код і виносить весь цей функціонал додавання модифікаторів від ваших очей.

> Користуючись нагодою, хочу сказати, що плагін дійсно неймовірно легкий і простий, нічого складного в коді немає. Трохи більше, ніж у прикладі вище і все. Тому (`Contributions welcome`) участь в проекті вітається. Ми винесли його у відкритий доступ не тому що ми зробили щось геніальне, а тому що нам в "РГ - Російська Газета" він дійсно допомагає в повсякденній роботі і сподіваємося буде корисним вам. Знову ж, якщо ви розробляєте згідно методологій.

## Чим корисний vue-mods-names

** Переваги **
1. Використовуючи плагін, кожен компонент вашої програми отримує можливість приймати модифікатори через props: mods. (Вам більше не потрібно додавати цю поведінку в окремі компоненти)
2. Ваш код стає менше. Вся робота з модифікаторами прихована в плагіні.
3. У будь-який компонент можна передавати один модифікатор рядком або будь-яку кількість модифікаторів в масиві.
4. Налаштування використання базового класу (дивіться розділ `" просунуте використання "`)

## Установка

Все як звичайно

```js
npm i vue-mods-names -D
```


## Використання

```js
import VueModsNames from 'vue-mods-names'

Vue.use(VueModsNames)
```

Якщо ви хочете поміняти префікс (за стандартом: `_`), то просто передайте його в опції плагіна:

```js
import VueModsNames from 'vue-mods-names'

Vue.use(VueModsNames, { prefix: '-' })
```

Після цього будь-який компонент в вашому додатку готовий використовувати модифікатори, якщо ви вкажете ім'я базового класу в якості аргументу директиви. Приклади нижче.

Декларуємо поведінку додаючи спеціальну директиву `v-mods-names` в шаблоні. `Good` - це назва базового класу, до якого будуть приєднуватися модифікатори.

`Good.vue`
```html
<!-- Шаблон компонента 'Good', який буде підключатися в різних місцях: -->
<div v-mods-names:good>Круто</div>
```
Тепер ми можемо використовувати компонент з різними модифікаторами:

`Головна сторінка`
```html
<Good mods="main" />
```

У підсумку ви отримаєте на головній сторінці компонент, у якого на виході будуть такі класи:

```html
<div class="good good_main">Круто</div>
```

> Усі модифікації компонента вказуються в стилях самого компонента. Наприклад:

```css
.good {}

.good_main {}

.good_big {}
```

Ви можете передавати масив модифікаторів:

```html
<Good :mods="['main', 'big']" />
```

На виході отримаємо це:

```html
<div class="good good_main good_big">Круто</div>
```

## Просунуте використання

### no-origin

Якщо вам раптом знадобилося використовувати тільки назви класів з модифікаторами, без базового класу, то вам на допомогу прийде модифікатор для директиви `v-mods-names`, який додається після назви вашого базового класу:

`Awesome.vue`
```html
<!-- Шаблон компонента Awesome -->
<div v-mods-names:awesome.no-origin>Шикарно</div>
```

Тепер при використанні вашого компонента таким чином:

```html
<Awesome :mods="['main', 'big']" />
```

Ви отримаєте це:

```html
<div class="awesome_main awesome_big"></div>
```

> Працює однаково як для одного модифікатора у вигляді рядка, так і для масиву модифікаторів

Ніхто не заважає вам використовувати це таким способом:

```html
<Awesome class="awesome" mods="big" />
```

На виході ви також отримаєте ваш базовий клас вказаний власноруч в шаблоні компонента і згенерований клас з модифікатором:

```html
<div class="awesome awesome_big"></div>
```

> Проте в цьому мало сенсу і набагато простіше написати в шаблоні директиву з базовим класом як в прикладі вище: `v-mods-names:awesome`

### Мені потрібно додати інші класи

Це дуже поширений кейс, коли вам потрібно додати якийсь клас після певних дій від користувача. Наприклад, ми обробляємо форму і в разі отримання помилки від сервера нам потрібно додати клас з модифікатором `error` до нашого компоненту.

```html
<div v-mods-names:input :class="classArr"></div>
```

```js
computed: {
  classArr () {
    // Якщо отримана помилка
    if (this.warrningValidation) {
      let newClasses = this.modsNames.slice()
      newClasses += ' input_warrning'
      return newClasses
    }
    return this.modsNames
  }
}
```

[KamilOcean](https://twitter.com/kamil_ocean)
