Skip to content

Latest commit

 

History

History
586 lines (425 loc) · 31 KB

README-RU.md

File metadata and controls

586 lines (425 loc) · 31 KB

Переводы

Этот документ предлагает для вас ряд правил по разработке компонентов Vue которые:

  • потом будет легче для вашей команды (или для вас в будущем) понять или найти что и как работает
  • ваш редактор кода (IDE, среда разработки) поймет с меньшим количеством ошибок и предложит лучшие подсказки
  • улучшит переиспользование в данном проекте и в других ваших проектах
  • лучше кешируются и выделяются в отдельные компоненты

Содержание

  • Модульная разработка
  • Наименование компонентов Vue
  • Выражения в компонентах должны быть простыми
  • Оставляйте свойства простыми
  • Правильно используйте свойства компонента
  • Определяйте this как component
  • Структура компонента
  • Именование событий
  • Избегайте this.$parent
  • Используйте this.$refs осторожно
  • Используйте ограниченные стили
  • Документируйте API компонента
  • Добавляйте демо
  • Форматируйте код файлов

Модульная разработка

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

Модуль по определению это небольшая ограниченная часть приложения. "Строительный блок", самодостаточный функционально. Организация Vue позволяет создавать подобные модули ориентируясь на визуальные компоненты.

Почему?

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

Как?

Старайтесь чтобы каждый Vue компонент соответствовал принципам FIRST:

  • решающий одну задачу,
  • независимый,
  • переиспользуемый,
  • небольшой,
  • простой в тестировании.

↑ наверх

Наименование компонентов Vue

Имя каждого компонента должно соответствовать следующим критериям:

  • Понятное: в меру детальным, в меру абстрактным
  • Короткое: не более 2-3 слов
  • Произносимое: чтобы его можно было упомянуть в обсуждении

Почему?

  • Имя компонента используется людьми и должно облегчать коммуникацию

Как?

<!-- правильно -->
<app-header></app-header>
<user-list></user-list>
<range-slider></range-slider>

<!-- неправильно -->
<btn-group></btn-group> <!-- короткое, но произносить - язык сломаешь -->
<ui-slider></ui-slider> <!-- все компоненты - так или иначе UI элементы, приставка не нужна -->
<slider></slider> <!--не соответствует спецификации HTML5 -->

↑ наверх

Выражения в компонентах должны быть простыми

Вы можете использовать инлайн-выражения в шаблонах Vue - это самые обычные Javascript выражения. Они дают максимальную свободу и мощность, однако из-за этого они могут стать слишком сложными. Не злоупотребляйте этим - оставляйте инлайн-выражения простыми.

Почему?

  • Сложные выражения сложнее прочесть и понять.
  • Инлайн-выражения нельзя переиспользовать, это очевидно, ведет дублированию кода и ухудшению его качества.
  • Редакторы и IDE обычно не могут парсить такие выражения, а значит у вас не будет автодополнения и валидации.

Как?

Простое правило - если код Javascript инлайн-выражения становится слишком сложным - выносите его как отдельный метод в блок methods или computed-свойство, соответственно в блок computed.

<!-- правильно -->
<template>
  <h1>
    {{ `${year}-${month}` }}
  </h1>
</template>
<script type="text/javascript">
  export default {
    computed: {
      month() {
        return this.twoDigits((new Date()).getUTCMonth() + 1);
      },
      year() {
        return (new Date()).getUTCFullYear();
      }
    },
    methods: {
      twoDigits(num) {
        return ('0' + num).slice(-2);
      }
    },
  };
</script>

<!-- неправильно -->
<template>
  <h1>
    {{ `${(new Date()).getUTCFullYear()}-${('0' + ((new Date()).getUTCMonth()+1)).slice(-2)}` }}
  </h1>
</template>

↑ наверх

Оставляйте свойства простыми

Хотя Vue и поддерживает передачу атрибутов в виде сложных объектов, старайтесь избегать этого. Старайтесь ограничиться простыми типами JavaScript и функциями для этого. Не передавайте сложные объекты в компоненты-наследники.

Почему?

  • Используя для каждого свойства отдельный атрибут - API вашего компонента будет более наглядным.
  • Такой подход совместим с API к которому мы все привыкли у нативных HTML(5) элементов.
  • Созданые вами атрибуты будет легче понять другим членам команды.
  • При передаче сложных объектов сразу не видно, какие из его свойств далее используются, - это затруднит рефакторинг.

Как?

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

<!-- правильно -->
<range-slider
  :values="[10, 20]"
  min="0"
  max="100"
  step="5"
  :on-slide="updateInputs"
  :on-end="updateResults">
</range-slider>

<!-- неправильно -->
<range-slider :config="complexConfigObject"></range-slider>

↑ наверх

Ограничивайте использование свойств компонента

Во Vue свойства компонента (props) это его API. Ясное и понятное API делает ваши компоненты более простыми для использования другими разработчиками.

Свойства передаются с использованием специальных атрибутов тега. Эти атрибуты могут быть либо указаны как пустые значения (:attr), либо присвоены строкам (:attr="value" или v-bind:attr="value"). Обратите внимание на подобные возможности при описании свойств.

Почему?

Грамотное использование свойств гарантирует, что компонент всегда будет отрабатывать без ошибок. Даже если в последствии ваши компоненты будут использоваться не так как вы предполагали изначально.

Как?

  • Используйте свойства по умолчанию для указания значений свойств.
  • Используйте свойство type для валидации значений свойства.
  • Всегда проверяйте что свойство определено прежде чем его использовать.
<template>
  <input type="range" v-model="value" :max="max" :min="min">
</template>
<script type="text/javascript">
  export default {
    props: {
      max: {
        type: Number, // это обеспечивает проверку, что свойство max будет типа Number
        default() { return 10; },
      },
      min: {
        type: Number,
        default() { return 0; },
      },
      value: {
        type: Number,
        default() { return 4; },
      },
    },
  };
</script>

↑ наверх

Определяйте this как component

В контексте кода компонента Vue this всегда означает экземпляр самого компонента. Таким образом если вам понадобится обратиться к ней в другом контексте сделайте так, чтобы this означало component.

То есть, не используйте устаревшие конструкции присваивания вроде const self = this;. Можно и нужно использовать component в Vue компонентах для этого.

Почему?

  • Присваивая this к переменной названной component напрямую укажет тем кто это будет использовать, что это означает сам компонент.

Как?

<script type="text/javascript">
export default {
  methods: {
    hello() {
      return 'hello';
    },
    printHello() {
      console.log(this.hello());
    }
  }
};
</script>

<!-- неправильно -->
<script type="text/javascript">
export default {
  methods: {
    hello() {
      return 'hello';
    },
    printHello() {
      const self = this; // не нужно
      console.log(self.hello());
    },
  },
};
</script>

↑ наверх

Структура компонента

Добейтесь, чтобы описание компонента было понятным и логичным.

Почему?

  • Экспортируемый объект (речь о .js файле или блоке <script> в .vue файле) компонента, построенный в каждом случае по одинаковым принципам, ускорит работу с ним других разработчиков и будет служить внутренним стандартом.
  • Если свойства будут расположены по алфавиту их будет легче просмотреть и найти нужное.
  • Группировка сходных свойств также облегчает чтение и ориентирование в коде, например props, data, computed; далее watch, и methods; далее lifecycle methods, и тд.
  • Используйте имя компонента name. Далее разработка с использованием vue devtools будет более удобной с именованными компонентами.
  • Используйте одну из отраслевых технологий для именования CSS элементов, например BEM.
  • Предпочтительный порядок расположения блоков в .vue файле: template, потом script и далее style. Потому что большую часть времени любой разработчик проводит в написании HTML и далее JavaScript.

Как?

Структура компонента, описание свойств в логичном порядке:

<template lang="html">
  <div class="Ranger__Wrapper">
    <!-- ... -->
  </div>
</template>

<script type="text/javascript">
  export default {
    // обязательно не забываем имя к.
    name: 'RangeSlider',
    // можем использовать композицию уже существующих к.
    extends: {},
    // перечисление свойств и переменных
    props: {
  bar: {}, // еще лучше если по-алфавиту
  foo: {},
  fooBar: {},
  },
    data() {},
    computed: {},
    // когда внутри используются другие к.
    components: {},
    // методы
    watch: {},
    methods: {},
    // методы жизненного цикла к.
    beforeCreate() {},
    mounted() {},
};
</script>

<style scoped>
  .Ranger__Wrapper { /* ... */ }
</style>

↑ наверх

Именование событий

В Vue все инлайн-выражения и методы компонента напрямую относятся к VM (ViewModel) и меняют ее состояние. При декларации собственных событий важно их грамотно называть, чтобы избежать сложности при дальнейшей разработке и использовании компонента.

Почему?

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

Как?

  • В названиях событий стоит использовать кебаб нотацию kebab-cased.
  • Название компонента должно быть уникальным и отражать что в нем происходит, например: upload-success, upload-error или dropzone-upload-success, dropzone-upload-error
  • В именах компонентов лучше использовать только существительные и глаголы, например: client-api-load, drive-upload-success (источник)

↑ наверх

Избегайте использования this.$parent

Vue поддерживает вложенности компонентов, поэтому дочерние компоненты могут обращаться к данным родителя. Обращение к внутреннему состоянию компонента снаружи нарушает принцип FIRST. Старайтесь избегать конструкции this.$parent. Возможны случаи, когда это разумный выход, но это слишком плохая практика, чтобы использовать его всегда.

Почему?

  • Компонент Vue, как и любой другой, должен работать изолированно. Если для работы требуется взаимодействия с соседними скоупами, то нарушается принцип компонентной разработки.
  • Если компоненту требуется обращение к соседям - такой компонент не может быть полноценно переиспользован.

Как?

  • Передавайте данные из родителя в дочерний компонент используя атрибуты и свойства.
  • Передавайте методы используя коллбеки и выражениях в атрибутах.
  • В обратную сторону: дочерние компоненты должны генерировать события, которые будет перехватывать родитель.

↑ наверх

Используйте this.$refs осторожно

Vue как и React поддерживает обращение к другим компонентам и html-элементам с использованием атрибута ref. Через обращение к this.$refs разработчик может получить доступ к контексту других компонентов или тегов. В большинстве случаев можно не использовать this.$refs для обращения к другим компонентам.

Почему?

  • Если компонент не работает в изоляции это признак плохого дизайна.
  • Для подавляющего большинства случаев, достаточно использовать свойства компонента и его события.

Как?

  • Серьезно относитесь к дизайну API ваших компонентов.
  • Старайтесь избегать умножений и ветвлений пути исполнения кода в компонентах. Наличие таких фрагментов является признаком того, что API не достаточно общее, либо вам нужно создать и использовать другие компоненты для других юзкейсов.
  • Используя компонент, обратите внимание на свойства: если какого-то из них не хватает, то добавьте их сами и/или создайте тикет, если это osc библиотека.
  • Тоже самое с событиями - если чего-то не хватает, значит другой разработчик (или вы сами, в прошлом) не добавил их. Для исправления добавьте отсутствующее или проверьте бизнес-логику компонента, возможно, это событие уже не используется, тогда его можно просто удалить.
  • Используйте this.$refs, только если других путей нет и вам никак не обойтись событиями и свойствами.
  • Если по-другому никак, то отдавайте предпочтение refs, а не jQuery или document.queryElement. Так вы останетесь на одном уровне абстракции (который даёт Vue) и не будете мешать их в трудно понимаемую кучу.
<!-- отлично, можно обойтись без ref -->
<range :max="max"
  :min="min"
  @current-value="currentValue"
  :step="1"></range>
<!-- тут придется использовать this.$refs -->
<modal ref="basicModal">
  <h4>Basic Modal</h4>
  <button class="primary" @click="$refs.basicModal.close()">Close</button>
</modal>
<button @click="$refs.basicModal.open()">Open modal</button>

<!-- Modal component -->
<template>
  <div v-show="active">
    <!-- ... -->
  </div>
</template>

<script>
  export default {
    // ...
    data() {
        return {
            active: false,
        };
    },
    methods: {
      open() {
        this.active = true;
      },
      hide() {
        this.active = false;
      },
    },
    // ...
  };
</script>
<!-- тут можно было обойтись событиями -->
<template>
  <range :max="max"
    :min="min"
    ref="range"
    :step="1"></range>
</template>

<script>
  export default {
    // ...
    methods: {
      getRangeCurrentValue() {
        return this.$refs.range.currentValue;
      },
    },
    // ...
  };
</script>

↑ наверх

Используйте ограниченные стили CSS

В Vue тег компонента является кастомным HTML-тегом, который может использоваться как корневой элемент CSS стилей (vertical-slider .list-element). Или имя компонента может быть использовано как префикс CSS класса всех стилей компонента (.vertical-slider .list-element).

Почему?

  • Ограничивать CSS стили областью компонента делает поведение UI более предсказуемым, а также предохраняет переопределение стилей других элементов на странице из-за сходства селекторов (т.н. "утечку стилей").
  • Использование одинакового имени для названия папки модуля, названия компонента и корневого CSS стиля, делает прозрачным для разработчиков, что это части одного целого.

Как?

Используйте имя компонента как неймспейс префикс используя методологии BEM и OOCSS и важно не пропускайте атрибут scoped на теге <style>.

Использование этого атрибута оставит инструкцию для компилятора Vue добавить дополнительную сигнатуру на каждый класс, присутствующий в стилях вашего компонента. Это позволит при парсинге браузером (если он поддерживает такую возможность) применять ваши стили к тегам, которые составляют ваш компонент по всему приложению и только к ним, предотвращая т.н. "утечку стилей".

<style scoped>
  /* правильно */
  .MyExample { }
  .MyExample li { }
  .MyExample__item { }

  /* неправильно */
  .My-Example { } /* не ограничен именем компонента или модуля, не соответствует спецификации BEM */
</style>

↑ наверх

Документируйте API компонента

Экземпляр Vue компонента создается при размещении элемента компонента в коде приложения. Дополнительная конфигурация экземпляра осуществляется при использовании атрибутов. Для того, чтобы компонент мог быть успешно переиспользован другими разработчиками, эти атрибуты и есть API вашего компонента. Они могут быть доходчиво описаны в сопроводительном файле README.md.

Почему?

  • Документация предлагает разработчику высокоуровневое описание компонента без необходимости вникать в его код. Это делает использование компонента более быстрым и простым.
  • API компонента в Vue это набор его атрибутов. Именно с их помощью он может быть дополнительно настроен. То есть именно атрибуты компонента являются важными для тех разработчиков, которые будут его в дальнейшем использовать.
  • Документация формализует API, показывает разработчикам какая часть функционала сохраняется для обратной совместимости при модификации кода компонента.
  • Название README.md это по факту отраслевой стандарт названия для документации, которую разработчику стоит прочесть прежде чем использовать проект. Многие платформы управления кодом (Github, Bitbucket, Gitlab) по умолчанию показывают содержание README-файла при просмотре контента любой директории.

Как?

Добавляйте README.md файл в папку с файлами одного компонента:

range-slider/
├── range-slider.vue
├── range-slider.less
└── README.md

В этом README файле можно описать функционал модуля и варианты использования. Для компонентов Vue самым полезным является описать атрибуты, т.к. именно они являются выражением API компонента.

↑ наверх

Добавляйте демо компонента

Добавьте index.html файл с демо вида компонента в разных конфигурациях показывая как компонент может быть использован.

Почему?

  • Наличие демо показывает, что модуль работает отдельно.
  • Демо помогает другим разработчикам посмотреть на результаты - что получится прежде чем разбираться с кодом и/или документацией.
  • Демо компонента исчерпывающе показывает различные варианты конфигурации его использования.

↑ наверх

Форматируйте код ваших файлов

Линтеры улучшают качество кода и это помогает отлавливать синтаксические ошибки. .vue файлы можно обрабатывать плагином eslint-plugin-html. Если вы используете vue-cli то ESLint является доступной опцией по умолчанию.

Почему?

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

Как?

Чтобы линтеры могли выделять Javascript код из ваших vue файлов, он должен быть внутри тега <script></script>. Также старайтесь сохранять инлайн-выражения простыми (см. выше) так как линтер не может их распарсить.

Настройте линтер, указав ему, что определена глобальная переменная vue в секции opts.

ESLint

ESLint для использования требуется плагин ESLint HTML чтобы извлечь (распарсить) Javascript из .vue файлов компонентов.

Настройки ESLint сохраняем в файле modules/.eslintrc (так чтобы редактор кода также мог его интерпретировать):

{
  "extends": "eslint:recommended",
  "plugins": ["html"],
  "env": {
    "browser": true
  },
  "globals": {
    "opts": true,
    "vue": true
  }
}

Запуск ESLint

eslint modules/**/*.vue

JSHint

JSHint может парсить HTML (используя --extra-ext) и выделять код в script (используя --extract=auto).

Настройки JSHint сохраняем в файле modules/.jshintrc (так чтобы редактор кода также мог его интерпретировать):

{
  "browser": true,
  "predef": ["opts", "vue"]
}

Запуск JSHint

jshint --config modules/.jshintrc --extra-ext=html --extract=auto modules/

Внимание: JSHint не работает с .vue, только .html.


Хотите поучаствовать?

Сделайте форк этого репозитория и далее предлагайте PR. Или просто создайте тикет.

Автор перевода

Mikhail Kuznetcov