Правила приоритета A: Важно
Примечание
Это руководство для Vue.js устарело и требует пересмотра. Если у вас есть вопросы или предложения, пожалуйста, откройте issue.
Эти правила помогут избежать ошибок, поэтому выучите их и соблюдайте во что бы то ни стало. Исключения возможны, но они должны быть очень редкими и делаться только теми, кто обладает экспертными знаниями JavaScript и Vue.
Используйте многословные имена компонентов
Имена пользовательских компонентов всегда должны быть многословными, за исключением корневых компонентов App
. Это предотвращает конфликты с существующими и будущими элементами HTML, поскольку все элементы HTML состоят из одного слова.
Bad
template
<!-- в предварительно скомпилированных шаблонах -->
<Item />
<!-- в DOM-шаблонах -->
<item></item>
Good
template
<!-- в предварительно скомпилированных шаблонах -->
<TodoItem />
<!-- в DOM-шаблонах -->
<todo-item></todo-item>
Используйте подробные определения пропсов
В зафиксированном коде определения пропсов всегда должны быть как можно более подробными, с указанием как минимум типа (типов).
Подробное объяснение
Подробные определения пропсов имеют два преимущества:
- Они документируют API компонента, чтобы было понятно, как его использовать.
- В процессе разработки Vue предупредит вас, если компонент будет предоставлен с неправильно отформатированными параметрами, что поможет вам выявить потенциальные источники ошибок.
Плохо
js
// Это нормально только при создании прототипов
const props = defineProps(['status'])
Хорошо
js
const props = defineProps({
status: String
})
js
// Ещё лучше!
const props = defineProps({
status: {
type: String,
required: true,
validator: (value) => {
return ['syncing', 'synced', 'version-conflict', 'error'].includes(
value
)
}
}
})
Используйте v-for
с ключом
key
с v-for
всегда требуется для компонентов, чтобы сохранить внутреннее состояние компонента в поддереве. Однако даже для элементов полезно поддерживать предсказуемое поведение, как, например, постоянство объекта в анимации.
Подробное объяснение
Допустим, у вас есть список дел:
js
const todos = ref([
{
id: 1,
text: 'Учимся использовать v-for'
},
{
id: 2,
text: 'Учимся использовать key'
}
])
Затем отсортируйте их в алфавитном порядке. При обновлении DOM Vue оптимизирует отрисовку, чтобы выполнить как можно меньше мутаций DOM. Это может означать удаление первого элемента todo, а затем добавление его в конец списка.
Проблема в том, что есть случаи, когда важно не удалять элементы, которые останутся в DOM. Например, вы можете захотеть использовать <transition-group>
для анимации сортировки списка или сохранения фокуса, если отображаемый элемент является <input>
. В этих случаях добавьте уникальный ключ для каждого элемента (например, :key="todo.id"
) подскажет Vue, как вести себя более предсказуемо.
По нашему опыту, лучше всегда добавлять уникальный ключ, чтобы вы и ваша команда просто не беспокоились об этих крайних случаях. Тогда в редких, критичных к производительности сценариях, где постоянство объектов не нужно, вы можете сделать сознательное исключение.
Плохо
template
<ul>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ul>
Хорошо
template
<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
Избегайте использования v-if
вместе с v-for
Никогда не используйте v-if
в том же элементе, что и v-for
..
Есть два распространённых случая, когда это может быть заманчиво:
Чтобы отфильтровать элементы в списке (например,
v-for="user in users" v-if="user.isActive"
). В этих случаях заменитеusers
новым вычисляемым свойством, которое возвращает ваш отфильтрованный список (например,activeUsers
).Чтобы не отображать список, если он должен быть скрыт (например,
v-for="user in users" v-if="shouldShowUsers"
). В этих случаях переместитеv-if
в элемент-контейнер (например,ul
,ol
).
Подробное объяснение
Когда Vue обрабатывает директивы, v-if
имеет более высокий приоритет, чем v-for
, так что этот шаблон:
template
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
выбросит ошибку, потому что директива v-if
будет проанализирована первой, а итерационная переменная user
в данный момент не существует.
Это можно исправить, выполнив итерацию по вычисляемому свойству, например, так:
js
const activeUsers = computed(() => {
return users.filter((user) => user.isActive)
})
template
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
В качестве альтернативы мы можем использовать тег <template>
с v-for
для обёртывания элемента <li>
:
template
<ul>
<template v-for="user in users" :key="user.id">
<li v-if="user.isActive">
{{ user.name }}
</li>
</template>
</ul>
Плохо
template
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
Хорошо
template
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
template
<ul>
<template v-for="user in users" :key="user.id">
<li v-if="user.isActive">
{{ user.name }}
</li>
</template>
</ul>
Используйте стилизацию с привязкой к компонентам
Для приложений стили в компоненте верхнего уровня App
и в компонентах компоновки могут быть глобальными, но все остальные компоненты всегда должны быть привязаны к конкретной области.
Это актуально только для Однофайловых компонентов. Они не требуют использования атрибута scoped
. Для масштабирования можно использовать CSS-модули, стратегию, основанную на классах, например BEM, или другую библиотеку/соглашение.
Библиотеки компонентов, однако, должны предпочесть стратегию, основанную на классах, вместо использования атрибута scoped
..
Это упрощает переопределение внутренних стилей, позволяя использовать понятные для человека имена классов, которые не имеют слишком высокой специфичности, но при этом с большой вероятностью не приведут к конфликту.
Подробное объяснение
Если вы разрабатываете большой проект, работаете с другими разработчиками или иногда включаете сторонние HTML/CSS (например, от Auth0), последовательная сортировка гарантирует, что ваши стили будут применяться только к тем компонентам, для которых они предназначены.
Помимо атрибута scoped
, использование уникальных имён классов может гарантировать, что CSS сторонних разработчиков не будет применяться к вашему собственному HTML. Например, во многих проектах используются имена классов button
, btn
или icon
, поэтому даже если вы не используете такую стратегию, как BEM, добавление префикса для конкретного приложения и/или компонента (например, ButtonClose-icon
) может обеспечить некоторую защиту.
Плохо
template
<template>
<button class="btn btn-close">×</button>
</template>
<style>
.btn-close {
background-color: red;
}
</style>
Хорошо
template
<template>
<button class="button button-close">×</button>
</template>
<!-- Using the `scoped` attribute -->
<style scoped>
.button {
border: none;
border-radius: 2px;
}
.button-close {
background-color: red;
}
</style>
template
<template>
<button :class="[$style.button, $style.buttonClose]">×</button>
</template>
<!-- Использование модулей CSS -->
<style module>
.button {
border: none;
border-radius: 2px;
}
.buttonClose {
background-color: red;
}
</style>
template
<template>
<button class="c-Button c-Button--close">×</button>
</template>
<!-- Использование конвенции BEM -->
<style>
.c-Button {
border: none;
border-radius: 2px;
}
.c-Button--close {
background-color: red;
}
</style>