Рекомендации beta

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Это предотвращает конфликты с существующими или будущими 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'
}
})

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

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

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

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

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

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

Плохо

// Этого достаточно лишь для прототипа
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>

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

Для приложений стили в корневом компоненте 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>

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

Всегда используйте префикс $_ для пользовательских приватных свойств в плагине, примеси, и т.п. Затем, чтобы избежать конфликтов с кодом других авторов, также включайте именованную область (например, $_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 () {
// ...
}
}
}

Правила приоритета 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.

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

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

  • HTML-элементы,
  • другие компоненты с Base-префиксом
  • сторонние UI-компоненты.

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

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

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

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

  • Поскольку имена компонентов всегда должны состоять из нескольких слов, это соглашение запрещает вам выбирать произвольный префикс для простых компонентов-обёрток (например, MyButton, VueButton).

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

    var requireComponent = require.context("./src", true, /^Base[A-Z]/)
    requireComponent.keys().forEach(function (fileName) {
    var baseComponentConfig = requireComponent(fileName)
    baseComponentConfig = baseComponentConfig.default || baseComponentConfig
    var baseComponentName = baseComponentConfig.name || (
    fileName
    .replace(/^.+\//, '')
    .replace(/\.\w+$/, '')
    )
    Vue.component(baseComponentName, baseComponentConfig)
    })

Плохо

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

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

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

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

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

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

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

  • Coffee with milk
  • Soup of the day
  • Visitor to the museum

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

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

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.
  • Конфликты имён (например, многочисленные компоненты ButtonDelete.vue) затрудняют быстрый переход к определённому компоненту в редакторе кода.
  • Рефакторинг становится более сложным, потому что поиска с заменой будет недостаточно, чтобы обновить относительные ссылки на перемещённый компонент.

Плохо

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. Причины:

  • Редкость, когда на глобальные компоненты ссылаются в JavaScript, поэтому следование соглашению для JavaScript имеет меньше смысла.
  • Эти приложения всегда включают в себе множество шаблонов внутри DOM, где 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
}
<WelcomeMessage greetingText="hi"/>

Хорошо

props: {
greetingText: String
}
<WelcomeMessage greeting-text="hi"/>

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

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

В 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:) следует использовать всегда или никогда.

Плохо

<input
v-bind:value="newTodoText"
:placeholder="newTodoInstructions"
>
<input
v-on:input="onInput"
@focus="onFocus"
>

Хорошо

<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"
>

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

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

Опции компонента/экземпляра должны быть упорядочены консистентно.

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

  1. Побочные эффекты (вызывает эффекты вне компонента)

    • el
  2. Глобальная осведомлённость (требует знаний вне компонента)

    • name
    • parent
  3. Тип компонента (изменяет тип компонента)

    • functional
  4. Модификаторы шаблона (изменение способа компиляции шаблонов)

    • delimiters
    • comments
  5. Зависимости шаблона (ресурсы, используемые в шаблоне)

    • components
    • directives
    • filters
  6. Композиция (объединение свойств в опциях)

    • extends
    • mixins
  7. Интерфейс (интерфейс компонента)

    • inheritAttrs
    • model
    • props/propsData
  8. Локальное состояние (локальные реактивные свойства)

    • data
    • computed
  9. События (коллбэки вызываемые реактивными событиями)

    • watch
    • События хуков жизненного цикла (в порядке их вызова)
  10. Нереактивные свойства (свойства экземпляра независимые от системы реактивности)

    • methods
  11. Рендеринг (декларативное описание вывода компонента)

    • template/render
    • renderError

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

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

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

  1. Определение (предоставляет параметры компонента)

    • is
  2. Отображение списка (создаёт несколько вариантов одного элемента)

    • v-for
  3. Условия (указывается рендерится/отображается ли элемент)

    • v-if
    • v-else-if
    • v-else
    • v-show
    • v-cloak
  4. Модификаторы рендеринга (изменяют способ рендеринга элемента)

    • v-pre
    • v-once
  5. Глобальная осведомлённость (требует знаний вне компонента)

    • id
  6. Уникальные атрибуты (атрибуты, требующие уникальных значений)

    • ref
    • key
    • slot
  7. Двусторонняя привязка (объединение привязки и событий)

    • v-model
  8. Другие атрибуты (все неуказанные связанные или несвязанные атрибуты)

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

    • v-on
  10. Содержимое (перезаписывает содержимое элемента)

    • v-html
    • v-text

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

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

Когда компоненты кажутся неразборчивыми и становятся трудными для чтения, то добавление пустых строк между многострочными свойствами может облегчить их беглое изучение просматривая взглядом. В некоторых редакторах, таких как 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 () {
// ...
}
}

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

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

Плохо

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

Хорошо

<!-- ComponentA.vue -->
<template>...</template>
<script>/* ... */</script>
<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>

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

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

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

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

Плохо

<div v-if="error">
Error: {{ error }}
</div>
<div v-else>
{{ results }}
</div>

Хорошо

<div v-if="error" key="search-status">
Error: {{ error }}
</div>
<div v-else key="search-results">
{{ results }}
</div>
<p v-if="error">
Error: {{ error }}
</p>
<div v-else>
{{ 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 предлагает не только централизованное место для управления состоянием приложения, но и также инструменты для организации, отслеживания и отладки изменений состояния.

Плохо

// 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>