vue2_rus

Рекомендации по стилю кода

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

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

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

Наконец, мы разделили правила на четыре категории:

Категории правил

Приоритет A: Важно

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

Приоритет B: Настоятельно рекомендуется

Эти правила помогут улучшить читаемость и/или опыт разработки в большинстве проектов. Ваш код всё равно будет работать, если вы нарушите их, но нарушения должны быть редкими и обоснованными.

Приоритет C: Рекомендуется

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

  1. тренировать свой мозг, чтобы легче разбираться в большинстве кода сообщества, с которым придётся столкнуться
  2. иметь возможность копировать и использовать большинство примеров кода сообщества без изменений
  3. чаще находить новых сотрудников, уже знакомых с предпочитаемым стилем кода, по крайней мере, в отношении Vue

Приоритет D: Используйте с осторожностью

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

Правила приоритета A: Важно (Предотвращение ошибок)

Имена компонентов из нескольких слов важно

Имена компонентов должны всегда состоять из нескольких слов, за исключением корневого компонента App и встроенных компонентов самого Vue, например, <transition> или <component>.

Это предотвращает конфликты с существующими или будущими HTML-элементами, поскольку все HTML-элементы именуются одним словом.

Плохо

Vue.component('todo', {
  // ...
})
export default {
  name: 'Todo'
  // ...
}

Хорошо

Vue.component('todo-item', {
  // ...
})
export default {
  name: 'TodoItem'
  // ...
}

Данные компонента важно

Свойство data компонента должно быть функцией.

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

Подробное объяснение

Когда значением data будет объект, он будет использован для всех экземпляров компонента. Представьте, например, компонент TodoList с таким набором данных:

data: {
  listTitle: '',
  todos: []
}

Мы можем захотеть повторно использовать этот компонент, позволяя пользователям использовать несколько списков (например, для покупок, списков желаний, ежедневных дел и т.п.). Однако есть проблема. Поскольку каждый экземпляр компонента ссылается на один и тот же объект данных, изменение названия одного списка также изменит заголовок всех остальных списков. То же самое случится и при добавлении/изменении/удалении элемента списка.

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

data: function () {
  return {
    listTitle: '',
    todos: []
  }
}

Плохо

Vue.component('some-comp', {
  data: {
    foo: 'bar'
  }
})
export default {
  data: {
    foo: 'bar'
  }
}

Хорошо

Vue.component('some-comp', {
  data: function() {
    return {
      foo: 'bar'
    }
  }
})
// В .vue-файле
export default {
  data() {
    return {
      foo: 'bar'
    }
  }
}
// Допускается использовать объект напрямую
// в корневом экземпляре Vue, поскольку только
// один экземпляр будет существовать.
new Vue({
  data: {
    foo: 'bar'
  }
})

Определение входных параметров важно

Входные параметры должны быть определены как можно более подробно.

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

Подробное объяснение

Подробное определение входных параметров имеет два преимущества:

Плохо

// Этого достаточно лишь для прототипа
props: ['status']

Хорошо

props: {
  status: String
}
// Ещё лучше!
props: {
  status: {
    type: String,
    required: true,
    validator: function (value) {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].indexOf(value) !== -1
    }
  }
}

Уникальные ключи для v-for важно

Всегда используйте key с v-for.

key с v-for всегда обязателен для компонентов, для поддержания внутреннего состояния компонента и его поддерева. Даже для элементов это хорошая практика для поддержания предсказуемого поведения, такого как согласованности объекта в анимации.

Подробное объяснение

Представим, что у нас есть список различных todo:

data: function () {
  return {
    todos: [
      {
        id: 1,
        text: 'Изучить, как использовать v-for'
      },
      {
        id: 2,
        text: 'Изучить, как использовать key'
      }
    ]
  }
}

Затем вы сортируете их по алфавиту. При обновлении DOM, Vue будет оптимизировать отрисовку для выполнения самых дешёвых изменений DOM. Это может означать удаление первого элемента списка, а затем добавление его снова в конце списка.

Проблема в том, что бывают случаи, когда важно не удалять элементы, которые останутся в DOM. Например, вы можете использовать <transition-group> для анимации сортировки списка, или удержании фокуса, если отображаемый элемент является <input>. В этих случаях добавление уникального ключа для каждого элемента (например, :key="todo.id") подскажет Vue, как вести себя более предсказуемо.

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

Плохо

<ul>
  <li v-for="todo in todos">
    {{ todo.text }}
  </li>
</ul>

Хорошо

<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>

Избегайте использования v-if с v-for важно

Никогда не используйте v-if на том же элементе, что и v-for.

Есть два распространённых случая, когда это может быть заманчиво:

Когда Vue обрабатывает директивы, v-for имеет более высокий приоритет, чем v-if, поэтому такой шаблон:

<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

Будет аналогичен подобному:

this.users.map(function(user) {
  if (user.isActive) {
    return user.name
  }
})

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

Заменив это отображением вычисляемого свойства, подобным такому:

computed: {
  activeUsers: function () {
    return this.users.filter(function (user) {
      return user.isActive
    })
  }
}
<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

Мы получаем следующие преимущества:

Мы получаем такие же преимущества обновив подобное:

<ul>
  <li
    v-for="user in users"
    v-if="shouldShowUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

до такого:

<ul v-if="shouldShowUsers">
  <li
    v-for="user in users"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

Перемещая v-if в элемент контейнера, мы больше не проверяем shouldShowUsers для каждого пользователя в списке. Вместо этого мы проверяем его один раз и даже не выполняем v-for если значение shouldShowUsers будет false.

Плохо

<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
<ul>
  <li
    v-for="user in users"
    v-if="shouldShowUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

Хорошо

<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
<ul v-if="shouldShowUsers">
  <li
    v-for="user in users"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

Местные стили компонента важно

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

Это относится только к однофайловым компонентам. Это не требует использования атрибута scoped. Область действия стилей может ограничиваться через CSS-модули, стратегию на основе именования классов, такой как БЭМ, или другой библиотекой/соглашением.

Однако библиотеки компонентов должны предпочитать использовать стратегию на основе именования классов вместо использования атрибута scoped.

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

Подробное объяснение

Если вы разрабатываете большой проект, работая совместно с другими разработчиками или иногда используете сторонний HTML/CSS (например, от Auth0), консистентное ограничение области позволит гарантировать, что ваши стили применяются только к компонентам, для которых они предназначены.

Помимо атрибута scoped, использование уникальных имён классов может помочь гарантировать, что сторонний CSS не применяется к вашему собственному HTML. Например, многие проекты используют классы button, btn или icon, поэтому даже если вы не используете стратегию, такую как БЭМ, то добавление приставки приложения и/или компонента (например, ButtonClose-icon) может обеспечить некоторую защиту.

Плохо

<template>
  <button class="btn btn-close">X</button>
</template>

<style>
.btn-close {
  background-color: red;
}
</style>

Хорошо

<template>
  <button class="button button-close">X</button>
</template>

<!-- Использование атрибута `scoped` -->
<style scoped>
.button {
  border: none;
  border-radius: 2px;
}

.button-close {
  background-color: red;
}
</style>
<template>
  <button :class="[$style.button, $style.buttonClose]">X</button>
</template>

<!-- Использование CSS-модулей -->
<style module>
.button {
  border: none;
  border-radius: 2px;
}

.buttonClose {
  background-color: red;
}
</style>
<template>
  <button class="c-Button c-Button--close">X</button>
</template>

<!-- Использование методологии БЭМ -->
<style>
.c-Button {
  border: none;
  border-radius: 2px;
}

.c-Button--close {
  background-color: red;
}
</style>

Именование закрытых свойств важно

Используйте область видимости модуля, чтобы приватные функции были недоступны извне. Если это невозможно, всегда используйте приставку $_ для самодельных свойств в добавке, примеси и т.п. Таким образом, они не рассматриваться как публичный API-интерфейс. Затем, чтобы избежать конфликтов с кодом других авторов, также включайте именованную область (например, $_yourPluginName_).

Подробное объяснение

Vue использует приставку _ для определения собственных закрытых свойств, поэтому использование одной и той же приставки (например, _update) может привести к перезаписи свойства экземпляра. Даже если вы проверяете и Vue в настоящее время не использует определённое имя свойства, нет гарантий, что конфликт не возникнет в более поздних версиях.

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

Вместо этого мы рекомендуем совмещать две приставки в $_, как соглашение для самодельных закрытых свойств, которые гарантируют отсутствие конфликтов с Vue.

Плохо

var myGreatMixin = {
  // ...
  methods: {
    update: function() {
      // ...
    }
  }
}
var myGreatMixin = {
  // ...
  methods: {
    _update: function() {
      // ...
    }
  }
}
var myGreatMixin = {
  // ...
  methods: {
    $update: function() {
      // ...
    }
  }
}
var myGreatMixin = {
  // ...
  methods: {
    $_update: function() {
      // ...
    }
  }
}

Хорошо

var myGreatMixin = {
  // ...
  methods: {
    $_myGreatMixin_update: function() {
      // ...
    }
  }
}
// Ещё лучше!
var myGreatMixin = {
  // ...
  methods: {
    publicMethod() {
      // ...
      myPrivateFunction()
    }
  }
}

function myPrivateFunction() {
  // ...
}

export default myGreatMixin

Правила приоритета B: Настоятельно рекомендуется (Улучшение читаемости)

Файлы компонентов настоятельно рекомендуется

Всякий раз, когда система сборки позволяет конкатенировать файлы, каждый компонент должен быть в собственном файле.

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

Плохо

Vue.component('TodoList', {
  // ...
})

Vue.component('TodoItem', {
  // ...
})

Хорошо

components/
|- TodoList.js
|- TodoItem.js
components/
|- TodoList.vue
|- TodoItem.vue

Именование однофайловых компонентов настоятельно рекомендуется

Имена файлов однофайловых компонентов должны быть всегда в PascalCase или всегда в kebab-case.

PascalCase лучше всего работает с автодополнением в редакторах кода, поскольку он согласуется с тем, как мы ссылаемся на компоненты в JS(X) и шаблонах. Тем не менее, смешанные имена файлов иногда могут создавать проблемы для нечувствительных к регистру файловых систем, поэтому kebab-case также вполне приемлем.

Плохо

components/
|- mycomponent.vue
components/
|- myComponent.vue

Хорошо

components/
|- MyComponent.vue
components/
|- my-component.vue

Именование базовых компонентов настоятельно рекомендуется

Базовые компоненты (известные как презентационные, глупые или чистые компоненты) которые применяют специфичные для вашего приложения стили или соглашения должны начинаться с определённого префикса, такого как Base, App или V.

Подробное объяснение

Эти компоненты закладывают основу для согласованности стилей и поведения в вашем приложении. Они могут содержать только:

Но они никогда не содержат глобальное состояние (например, из хранилища Vuex).

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

Некоторые преимущества этого соглашения:

Плохо

components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue

Хорошо

components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
components/
|- AppButton.vue
|- AppTable.vue
|- AppIcon.vue
components/
|- VButton.vue
|- VTable.vue
|- VIcon.vue

Именование компонентов, используемых в единственном экземпляре настоятельно рекомендуется

Компоненты, которые должны иметь только один активный экземпляр, следует начинать именовать с приставки The, обозначая таким образом что он может быть только один.

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

Плохо

components/
|- Heading.vue
|- MySidebar.vue

Хорошо

components/
|- TheHeading.vue
|- TheSidebar.vue

Именование тесно связанных компонентов настоятельно рекомендуется

Дочерние компоненты, тесно связанные с родителями, должны включать имя родительского компонента в качестве префикса.

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

Подробное объяснение

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

components/
|- TodoList/
   |- Item/
      |- index.vue
      |- Button.vue
   |- index.vue

или:

components/
|- TodoList/
   |- Item/
      |- Button.vue
   |- Item.vue
|- TodoList.vue

Это не рекомендуется, так как это приводит к:

Плохо

components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue

Хорошо

components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue

Порядок слов в именах компонентов настоятельно рекомендуется

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

Подробное объяснение

Вам может быть интересно:

«Почему мы заставляем называть компоненты менее естественным языком?»

На естественном английском прилагательные и другие описатели обычно располагаются перед существительными, в то время как исключения требуют слов-соединителей. Например:

Вы определённо можете включать эти слова-соединители в именах компонентах если хотите, но порядок всё ещё важен.

Также обратите внимание, то что считается «высоким уровнем» будет относиться к вашему приложению. Например, представьте приложение с формой для поиска. Оно может содержать компоненты наподобие таких:

components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue

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

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputExcludeGlob.vue
|- SearchInputQuery.vue
|- SettingsCheckboxLaunchOnStartup.vue
|- SettingsCheckboxTerms.vue

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

Возможно вы захотите решить эту проблему по-другому, переместив все компоненты поиска в отдельный каталог «search», а потом все компоненты параметров в каталог «settings». Мы рекомендуем применять этот подход только в очень больших приложениях (например, из более 100 компонентов) по следующим причинам:

Плохо

components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue

Хорошо

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue

Самозакрывающиеся теги компонентов настоятельно рекомендуется

Компоненты без содержимого должны быть самозакрывающимися тегами в однофайловых компонентах, строковых шаблонах и JSX — но никогда в DOM-шаблонах.

Самозакрывающиеся теги компонентов сообщают, что у них не только нет содержимого, но и сообщает что и не должны иметь содержимого. Это разница между пустой страницей в книге и страницей с надписью: «Эта страница намеренно оставлена пустой». Ваш код также станет более лаконичным без ненужного закрывающего тега.

К сожалению, HTML не разрешает пользовательским элементам быть самозакрывающимися — только официальные «void» элементы. Вот почему эта стратегия возможна только тогда, когда компилятор шаблонов Vue может достичь шаблона перед DOM, а затем предоставить DOM-совместимый HTML.

Плохо

<!-- В однофайловых компонентах, строковых шаблонах и JSX -->
<MyComponent></MyComponent>
<!-- В DOM-шаблонах -->
<my-component/>

Хорошо

<!-- В однофайловых компонентах, строковых шаблонах и JSX -->
<MyComponent/>
<!-- В DOM-шаблонах -->
<my-component></my-component>

Стиль именования компонентов в шаблонах настоятельно рекомендуется

В большинстве проектов имена компонентов всегда должны быть в PascalCase в однофайловых компонентах и строковых шаблонах — но в kebab-case в случае DOM-шаблонов.

PascalCase имеет следующие преимущества перед kebab-case:

К сожалению, из-за нечувствительности HTML к регистру, DOM-шаблоны должны по-прежнему использовать kebab-case.

Также обратите внимание, что если вы уже вложили значительные силы в kebab-case, согласованность с соглашениями HTML и возможность использования такого же написания во всех ваших проектах, то это может быть более важным, чем преимущества, перечисленные выше. В этих случаях допускается использовать kebab-case повсюду.

Плохо

<!-- В однофайловых компонентах и строковых шаблонах -->
<mycomponent/>
<!-- В однофайловых компонентах и строковых шаблонах -->
<myComponent/>
<!-- В DOM-шаблонах -->
<MyComponent></MyComponent>

Хорошо

<!-- В однофайловых компонентах и строковых шаблонах -->
<MyComponent/>
<!-- В DOM-шаблонах -->
<my-component></my-component>

ИЛИ

<!-- Везде -->
<my-component></my-component>

Стиль именования компонентов в JS/JSX настоятельно рекомендуется

Стиль именования компонентов в JS/JSX всегда должен быть PascalCase, хотя они могут быть в kebab-case внутри строк для простых приложений, которые используют только глобальную регистрацию компонентов через Vue.component.

Подробное объяснение

В JavaScript PascalCase — это соглашение для классов и конструкторов прототипов — по существу всё, что может иметь разные экземпляры. Компоненты Vue также могут иметь экземпляры, поэтому также имеет смысл использовать PascalCase. В качестве дополнительного преимущества, использование PascalCase в JSX (и шаблонах) позволяет изучающим код легче различать компоненты от HTML-элементов.

Однако, для приложений, которые используют только глобальные определения компонентов через Vue.component, мы рекомендуем вместо него использовать kebab-case. Причины:

Плохо

Vue.component('myComponent', {
  // ...
})
import myComponent from './MyComponent.vue'
export default {
  name: 'myComponent'
  // ...
}
export default {
  name: 'my-component'
  // ...
}

Хорошо

Vue.component('MyComponent', {
  // ...
})
Vue.component('my-component', {
  // ...
})
import MyComponent from './MyComponent.vue'
export default {
  name: 'MyComponent'
  // ...
}

Использование полных слов при именовании компонентов настоятельно рекомендуется

Имена компонентов должны состоять из полных слов, а не аббревиатур.

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

Плохо

components/
|- SdSettings.vue
|- UProfOpts.vue

Хорошо

components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue

Стиль именования входных параметров настоятельно рекомендуется

Входные параметры должны всегда использовать camelCase при определении, но kebab-case в шаблонах и JSX.

Мы просто придерживаемся соглашений каждого языка. Для JavaScript использовать camelCase является более естественным. Для HTML — kebab-case.

Плохо

props: {
  'greeting-text': String
}

Хорошо

props: {
  greetingText: String
}

Элементы с несколькими атрибутами настоятельно рекомендуется

Элементы с несколькими атрибутами должны располагаться на нескольких строках, по одному атрибуту на строку.

В JavaScript написание объектов с несколькими свойствами в несколько строк считается хорошей практикой, потому что при таком написании её гораздо легче читать. Наши шаблоны и JSX стоит рассматривать также.

Плохо

<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<MyComponent foo="a" bar="b" baz="c"/>

Хорошо

<img
  src="https://vuejs.org/images/logo.png"
  alt="Vue Logo"
>
<MyComponent
  foo="a"
  bar="b"
  baz="c"
/>

Простые выражения в шаблонах настоятельно рекомендуется

Шаблоны компонентов должны содержать только простые выражения, а более комплексные должны быть вынесены в вычисляемые свойства или методы.

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

Плохо

{{
  fullName.split(' ').map(
      function (word) {
        return word[0].toUpperCase() + word.slice(1)
      }
  ).join(' ')
}}

Хорошо

<!-- В шаблоне -->
{{ normalizedFullName }}
// Комплексное выражение было вынесено в вычисляемое свойство
computed: {
  normalizedFullName: function () {
    return this.fullName.split(' ').map(function (word) {
      return word[0].toUpperCase() + word.slice(1)
    }).join(' ')
  }
}

Простые вычисляемые свойства настоятельно рекомендуется

Комплексные вычисляемые свойства должны быть разделены на максимально простые свойства.

Подробное объяснение

Проще говоря, хорошие вычисляемые свойства будет:

Плохо

computed: {
  price: function () {
    var basePrice = this.manufactureCost / (1 - this.profitMargin)
    return (
      basePrice -
      basePrice * (this.discountPercent || 0)
    )
  }
}

Хорошо

computed: {
  basePrice: function () {
    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
    return this.basePrice - this.discount
  }
}

Значения атрибутов в кавычках настоятельно рекомендуется

Непустые значения HTML-атрибутов должны быть обрамлены кавычками (одинарными или двойными, в зависимости от того, что не используется в JS).

Хотя значения атрибутов без каких-либо пробелов не требуют иметь кавычки в HTML, эта практика зачастую приводит к избеганию использования пробелов, делая значения атрибутов менее читабельными.

Плохо

<input type=text>
<AppSidebar :style={width:sidebarWidth+'px'}>

Хорошо

<input type="text">
<AppSidebar :style="{ width: sidebarWidth + 'px' }">

Сокращённая запись директив настоятельно рекомендуется

Сокращённую запись директив (: для v-bind:, @ для v-on: и # для v-slot) следует использовать всегда или никогда.

Плохо

<input
  v-bind:value="newTodoText"
  :placeholder="newTodoInstructions"
>
<input
  v-on:input="onInput"
  @focus="onFocus"
>
<template v-slot:header>
  <h1>Здесь может быть заголовок страницы</h1>
</template>

 <template #footer>
  <p>Здесь контактная информация</p>
</template>

Хорошо

<input
  :value="newTodoText"
  :placeholder="newTodoInstructions"
>
<input
  v-bind:value="newTodoText"
  v-bind:placeholder="newTodoInstructions"
>
<input
  @input="onInput"
  @focus="onFocus"
>
<input
  v-on:input="onInput"
  v-on:focus="onFocus"
>
<template v-slot:header>
  <h1>Здесь может быть заголовок страницы</h1>
</template>

 <template v-slot:footer>
  <p>Здесь контактная информация</p>
</template>
<template #header>
  <h1>Здесь может быть заголовок страницы</h1>
</template>

 <template #footer>
  <p>Здесь контактная информация</p>
</template>

Правила приоритета C: Рекомендуется (Уменьшение произвольных выборов и накладных расходов)

Порядок настроек компонента/экземпляра рекомендуется

Параметры компонента/экземпляра должны быть упорядочены согласованно.

Это порядок по умолчанию, который мы рекомендуем для настроек компонентов. Они разделены на категории, поэтому вы поймёте, где добавлять новые свойства из добавок.

  1. Побочные эффекты (вызывает эффекты вне компонента)
  1. Глобальная осведомлённость (требует знаний вне компонента)
  1. Тип компонента (изменяет тип компонента)
  1. Модификаторы шаблона (изменение способа компиляции шаблонов)
  1. Зависимости шаблона (ресурсы, используемые в шаблоне)
  1. Композиция (объединение свойств в настройках)
  1. Интерфейс (интерфейс компонента)
  1. Местное состояние (местные реактивные свойства)
  1. События (обратновызовы вызываемые реактивными событиями)
  1. Нереактивные свойства (свойства экземпляра независимые от системы реактивности)
  1. Отрисовка (декларативное описание вывода компонента)

Порядок атрибутов элемента рекомендуется

Атрибуты элементов (в том числе компонентов) должны быть упорядочены согласованно.

Этот порядок по умолчанию мы рекомендуем для настроек компонентов. Они разделены на категории, поэтому вы узнаете, где добавлять пользовательские атрибуты и директивы.

  1. Определение (предоставляет параметры компонента)
  1. Отображение списка (создаёт несколько вариантов одного элемента)
  1. Условия (указывается отрисовывается/отображается ли элемент)
  1. Изменители отрисовки (изменяют способ отрисовки элемента)
  1. Глобальная осведомлённость (требует знаний вне компонента)
  1. Уникальные атрибуты (атрибуты, требующие уникальных значений)
  1. Двусторонняя привязка (объединение привязки и событий)
  1. Другие атрибуты (все неуказанные связанные или несвязанные атрибуты)

  2. События (обработчики событий компонента)

  1. Содержимое (перезаписывает содержимое элемента)

Пустые строки между настроек компонента/экземпляра рекомендуется

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

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

Хорошо

props: {
  value: {
    type: String,
    required: true
  },

  focused: {
    type: Boolean,
    default: false
  },

  label: String,
  icon: String
},

computed: {
  formattedValue: function () {
    // ...
  },

  inputClasses: function () {
    // ...
  }
}
// Отсутствие пробелов не мешает, если компонент
// всё ещё легко читать и перемещаться по нему.
props: {
  value: {
    type: String,
    required: true
  },
  focused: {
    type: Boolean,
    default: false
  },
  label: String,
  icon: String
},
computed: {
  formattedValue: function () {
    // ...
  },
  inputClasses: function () {
    // ...
  }
}

Порядок секций в однофайловых компонентах рекомендуется

Однофайловые компоненты должны всегда использовать один порядок для корневых тегов секций <script>, <template> и <style>, заканчиваясь <style>, потому что всегда требуется хотя бы одна из двух других.

Плохо

<style>/* ... */</style>
<script>/* ... */</script>
<template>...</template>
<!-- ComponentA.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>

Хорошо

<!-- ComponentA.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>
<!-- ComponentA.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>

</div>

Правила приоритета D: Используйте с осторожностью (Потенциально опасные шаблоны)

v-if/v-else-if/v-else без key используйте с осторожностью

Обычно лучше использовать key вместе с v-if + v-else, если они являются одним и тем же типом элемента (например, когда оба элемента <div>).

По умолчанию Vue обновляет dom наиболее эффективно. Это означает, что при переключении между элементами одного и того же типа, он просто исправляет текущий элемент, а не заменяет его на новый. Это может привести к непреднамеренным побочным эффектам, если эти элементы не должны считаться одинаковыми.

Плохо

<div v-if="error">
  Ошибка: {{ error }}
</div>
<div v-else>
  {{ results }}
</div>

Хорошо

<div
  v-if="error"
  key="search-status"
>
  Ошибка: {{ error }}
</div>
<div
  v-else
  key="search-results"
>
  {{ results }}
</div>

Отбиратели элементов при использовании scoped используйте с осторожностью

Отбирателей элементов следует избегать при использовании scoped.

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

Подробное объяснение

Для ограничения области действия стилей Vue добавляет уникальный атрибут к элементам компонента, например, такой как data-v-f3f3eg9. Затем отбиратели изменяются так, чтобы воздействовали только на подходящие элементы с этим атрибутом (например, button[data-v-f3f3eg9]).

Проблема в том, что большое количество отбирателей атрибутов элементов (например, button[data-v-f3f3eg9]) будет значительно медленнее отбирателей классов (например, .btn-close[data-v-f3f3eg9]), поэтому отбиратели классов должны быть предпочтительными всегда, когда это возможно.

Плохо

<template>
  <button>X</button>
</template>

<style scoped>
button {
  background-color: red;
}
</style>

Хорошо

<template>
  <button class="btn btn-close">X</button>
</template>

<style scoped>
.btn-close {
  background-color: red;
}
</style>

Неявное общение между родительским и дочерними компонентами используйте с осторожностью

Входные параметры и события должны быть предпочтительным способом общения между родительским и дочерними компонентами, вместо использования this.$parent или изменения входных параметров.

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

Проблема в том, что есть также множество простых случаев, когда эти шаблоны могут показаться удобнее. Остерегайтесь: не соблазняйтесь кажущейся простоте (чтобы понять поток вашего состояния) для краткосрочной выгоды (написания чуть меньшего количества кода).

Плохо

Vue.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  template: '<input v-model="todo.text">'
})
Vue.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  methods: {
    removeTodo() {
      var vm = this
      vm.$parent.todos = vm.$parent.todos.filter(function(todo) {
        return todo.id !== vm.todo.id
      })
    }
  },
  template: `
    <span>
      {{ todo.text }}
      <button @click="removeTodo">
        X
      </button>
    </span>
  `
})

Хорошо

Vue.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  template: `
    <input
      :value="todo.text"
      @input="$emit('input', $event.target.value)"
    >
  `
})
Vue.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  template: `
    <span>
      {{ todo.text }}
      <button @click="$emit('delete')">
        X
      </button>
    </span>
  `
})

Управление состоянием приложения без flux используйте с осторожностью

Vuex должен быть предпочтительным способом для глобального управления состоянием приложения вместо использования this.$root или глобальной шины событий.

Управление состоянием через this.$root и/или использование глобальной шины событий может быть удобным для очень простых случаев, но не подходит для большинства приложений.

Vuex — официальная flux-подобная реализация для Vue, и предлагает не только централизованное место для управления состоянием, а также инструменты организации, отслеживания и отладки изменений состояния. Она хорошо внедряется в экосистему Vue (включая полную поддержку Vue DevTools).

Плохо

// main.js
new Vue({
  data: {
    todos: []
  },
  created: function() {
    this.$on('remove-todo', this.removeTodo)
  },
  methods: {
    removeTodo: function(todo) {
      var todoIdToRemove = todo.id
      this.todos = this.todos.filter(function(todo) {
        return todo.id !== todoIdToRemove
      })
    }
  }
})

Хорошо

// store/modules/todos.js
export default {
  state: {
    list: []
  },
  mutations: {
    REMOVE_TODO(state, todoId) {
      state.list = state.list.filter(todo => todo.id !== todoId)
    }
  },
  actions: {
    removeTodo({ commit, state }, todo) {
      commit('REMOVE_TODO', todo.id)
    }
  }
}
<!-- TodoItem.vue -->
<template>
  <span>
    {{ todo.text }}
    <button @click="removeTodo(todo)">
      X
    </button>
  </span>
</template>

<script>
import { mapActions } from 'vuex'

export default {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  methods: mapActions(['removeTodo'])
}
</script>