Règles de priorité B : Fortement recommandées
Ces règles améliorent la lisibilité et/ou l'expérience des développeurs dans la plupart des projets. Votre code fonctionnera toujours si vous les enfreignez, mais les violations doivent être rares et bien justifiées.
Fichiers de composants
Chaque fois qu'un système de build est disponible pour concaténer des fichiers, chaque composant doit être dans son propre fichier.
Cela vous aide à trouver plus rapidement un composant lorsque vous devez le modifier ou revoir comment l'utiliser.
À éviter
js
app.component('TodoList', {
// ...
})
app.component('TodoItem', {
// ...
})
OK
components/
|- TodoList.js
|- TodoItem.js
components/
|- TodoList.vue
|- TodoItem.vue
La casse des noms de composants
Le nom des composants monofichiers doit toujours être soit en PascalCase soit en kebab-case.
PascalCase fonctionne mieux avec l'auto-complétion dans les éditeurs de code, car elle est cohérente avec la façon dont nous référençons les composants en JS(X) et les templates, dans la mesure du possible. Cependant, le nom des fichiers à casse mixte peut parfois créer des problèmes sur les systèmes de fichiers insensibles à la casse, c'est pourquoi kebab-case est également parfaitement acceptable.
À éviter
components/
|- mycomponent.vue
components/
|- myComponent.vue
OK
components/
|- MyComponent.vue
components/
|- my-component.vue
Nom des composants de base
Les composants de base (a.k.a. présentation, muet, ou composant pure) qui appliquent un style et des conventions spécifiques à l'application doivent tous commencer par un préfixe spécifique, tel que Base
, App
, ou V
.
Explications détaillées
Ces composants jettent les bases d'un style et d'un comportement cohérents dans votre application. Ils peuvent seulement contenir :
- Des éléments HTML,
- D'autres composants de base, et
- Un composant UI tiers.
Mais ils ne contiendront jamais des états globaux (par exemple, provenant de Pinia ou Vuex).
Leurs noms incluent souvent le nom d'un élément qu'ils encapsulent (par exemple, BaseButton
, BaseTable
), à moins qu'aucun élément n'existe pour leur usage spécifique (par exemple BaseIcon
). Si vous créez des composants similaires pour un contexte plus spécifique, ils utiliseront presque toujours ces composants (par exemple, BaseButton
peut être utilisé dans ButtonSubmit
).
Quelques avantages de cette convention :
Lorsqu'ils sont classés par ordre alphabétique dans les éditeurs, les composants de base de votre application sont tous répertoriés ensemble, ce qui facilite leur identification.
Puisque les noms des composants doivent toujours être des mots composés, cette convention vous fait éviter d'avoir à choisir des préfixes arbitraires pour des composants simples (e.g. MyButton, VueButton).
Étant donné que ces composants sont fréquemment utilisés, vous pouvez simplement les rendre globaux au lieu de les importer partout. Un préfixe rend cela possible avec Webpack :
jsconst requireComponent = require.context( './src', true, /Base[A-Z]\w+\.(vue|js)$/ ) requireComponent.keys().forEach(function (fileName) { let baseComponentConfig = requireComponent(fileName) baseComponentConfig = baseComponentConfig.default || baseComponentConfig const baseComponentName = baseComponentConfig.name || fileName.replace(/^.+\//, '').replace(/\.\w+$/, '') app.component(baseComponentName, baseComponentConfig) })
À éviter
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
OK
components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
components/
|- AppButton.vue
|- AppTable.vue
|- AppIcon.vue
components/
|- VButton.vue
|- VTable.vue
|- VIcon.vue
Noms des composants étroitement liés
Les composants enfants étroitement couplés à leur parent doivent inclure le nom du composant parent comme préfixe.
Si un composant n'a de sens que dans le contexte d'un seul composant parent, cette relation doit être évidente dans son nom. Étant donné que les éditeurs organisent généralement les fichiers par ordre alphabétique, cela permet également de conserver ces fichiers associés les uns à côté des autres.
Explications détaillées
Vous pourriez être tenté de résoudre ce problème en imbriquant les composants enfants dans des répertoires nommés d'après leur parent. Par exemple :
components/
|- TodoList/
|- Item/
|- index.vue
|- Button.vue
|- index.vue
ou :
components/
|- TodoList/
|- Item/
|- Button.vue
|- Item.vue
|- TodoList.vue
Ceci n'est pas recommandé, car pourrait entraîner :
- De nombreux fichiers avec des noms similaires, ce qui rend le changement rapide de fichier dans les éditeurs de code plus difficile.
- De nombreux sous-répertoires imbriqués, ce qui augmente le temps nécessaire pour parcourir les composants dans la barre latérale d'un éditeur.
À éviter
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue
OK
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue
Ordre des mots dans les noms des composants
Les noms des composants doivent commencer par les mots de plus haut niveau (souvent les plus généraux) et se terminer par des mots de modification descriptifs.
Explications détaillées
Vous vous demandez peut-être :
"Pourquoi forcerions-nous les noms de composants à utiliser un langage moins naturel ?"
En anglais naturel, les adjectifs et autres descripteurs apparaissent généralement avant les noms, tandis que les exceptions nécessitent des mots connecteurs. Par exemple :
- Coffee with milk
- Soup of the day
- Visitor to the museum
Vous pouvez certainement inclure ces connecteurs dans les noms de composants si vous le souhaitez, mais l'ordre est toujours important.
Notez également que ce qui est considéré comme "de plus haut niveau" sera contextuel à votre application. Par exemple, imaginez une application avec un formulaire de recherche. Il peut inclure des composants comme celui-ci :
components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue
Comme vous le remarquerez peut-être, il est assez difficile de voir quels composants sont spécifiques à la recherche. Renommons maintenant les composants selon la règle :
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputExcludeGlob.vue
|- SearchInputQuery.vue
|- SettingsCheckboxLaunchOnStartup.vue
|- SettingsCheckboxTerms.vue
Étant donné que les éditeurs organisent généralement les fichiers par ordre alphabétique, toutes les relations importantes entre les composants sont désormais évidentes en un coup d'œil.
Vous pourriez être tenté de résoudre ce problème différemment, en imbriquant tous les composants de recherche dans un répertoire "recherche", puis tous les composants de paramètres dans un répertoire "paramètres". Nous vous recommandons de ne considérer cette approche que dans les très grandes applications (par exemple, plus de 100 composants), pour les raisons suivantes :
- Il faut généralement plus de temps pour naviguer dans les sous-répertoires imbriqués que pour parcourir un seul répertoire
components
. - Les conflits de nom (par exemple, plusieurs composants ButtonDelete.vue) rendent plus difficile la navigation rapide vers un composant spécifique dans un éditeur de code.
- Le refactoring devient plus difficile, car la recherche et le remplacement ne sont souvent pas suffisants pour mettre à jour les références relatives à un composant déplacé.
À éviter
components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue
OK
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
Composants auto-fermants
Les composants sans contenu doivent être auto-fermants dans les composants monofichiers, dans les templates, et dans JSX - mais jamais dans les templates du DOM.
Les composants auto-fermants n'indiquent pas seulement qu'ils n'ont pas de contenu, mais aussi qu'ils ne sont pas censés en avoir. C'est la différence entre une page blanche dans un livre et une autre intitulée «Cette page est laissée vierge intentionnellement». Votre code est également plus propre sans la balise de fermeture inutile.
Malheureusement, HTML n'autorise pas que les éléments personnalisés soient auto-fermants - seulement les éléments officiels "void". C'est pourquoi la stratégie n'est possible que lorsque le compilateur de templates de Vue peut atteindre le template avant le DOM, puis servir le HTML conforme aux spécifications.
À éviter
template
<!-- Dans les composants monofichiers, string templates, et JSX -->
<MyComponent></MyComponent>
template
<!-- Dans les templates du DOM -->
<my-component/>
OK
template
<!-- Dans les composants monofichiers, string templates, et JSX -->
<MyComponent/>
template
<!-- Dans les templates du DOM -->
<my-component></my-component>
La casse des noms de composants dans les templates
Dans la plupart des projets, les noms de composants doivent toujours être en PascalCase dans les composants monofichiers et dans les string templates - mais en kebab-case dans les templates du DOM.
PascalCase a quelques avantages par rapport au kebab-case :
- Les éditeurs peuvent compléter automatiquement les noms de composants dans les templates, car le PascalCase est également utilisé en JavaScript.
<MyComponent>
est visuellement plus distinct d'un élément HTML que<my-component>
, car il y a deux différences de caractères (les deux majuscules), plutôt qu'une seule (un trait d'union).- Si vous utilisez des éléments personnalisés non-Vue dans vos templates, tels qu'un Web Component, le PascalCase garantit que vos composants Vue restent clairement visibles.
Malheureusement, en raison de l'insensibilité à la casse de HTML, les templates du DOM doivent toujours utiliser le kebab-case.
Notez également que si vous êtes déjà beaucoup investi dans l'usage du kebab-case, la cohérence avec les conventions HTML et la possibilité d'utiliser la même casse dans tous vos projets peuvent être plus importantes que les avantages énumérés ci-dessus. Dans ces cas, l'utilisation de kebab-case partout est également acceptable.
À éviter
template
<!-- Dans les composants monofichiers, string templates, et JSX -->
<mycomponent/>
template
<!-- Dans les composants monofichiers, string templates, et JSX -->
<myComponent/>
template
<!-- Dans les templates du DOM -->
<MyComponent></MyComponent>
OK
template
<!-- Dans les composants monofichiers, string templates, et JSX -->
<MyComponent/>
template
<!-- Dans les templates du DOM -->
<my-component></my-component>
OU
template
<!-- Partout -->
<my-component></my-component>
La casse des noms de composants en JS/JSX
Les noms de composants en JS/JSX devraient toujours être en PascalCase, quoiqu'ils puissent être en kebab-case dans des strings pour des applications plus simples qui n'utilisent que l'enregistrement global des composants via app.component
.
Explications détaillées
En JavaScript, le PascalCase est la convention pour les classes et les constructeurs de prototypes - essentiellement, tout ce qui peut avoir des instances distinctes. Les composants Vue ont également des instances, il est donc logique d'utiliser également PascalCase. Comme avantage supplémentaire, l'utilisation de PascalCase dans JSX (et les templates) permet aux gens qui lisent le code de distinguer plus facilement les composants et les éléments HTML.
Cependant, pour les applications qui utilisent uniquement les définitions de composants globales via app.component
, nous recommandons plutôt le kebab-case. Les raisons sont :
- Il est rare que des composants globaux soient référencés en JavaScript, donc suivre une convention pour JavaScript a peu de sens.
- Ces applications incluent toujours de nombreux templates du DOM, où kebab-case doit être utilisée.
À éviter
js
app.component('myComponent', {
// ...
})
js
import myComponent from './MyComponent.vue'
js
export default {
name: 'myComponent'
// ...
}
js
export default {
name: 'my-component'
// ...
}
OK
js
app.component('MyComponent', {
// ...
})
js
app.component('my-component', {
// ...
})
js
import MyComponent from './MyComponent.vue'
js
export default {
name: 'MyComponent'
// ...
}
Nom des composants en mot entier
Les noms des composants devraient être écrit avec des mots entiers plutôt ques des abréviations.
L'auto-complétion dans les éditeurs de code fait gagner énormément de temps, tandis que la clarté qu'ils fournissent est inestimable. Les abréviations peu courantes, en particulier, doivent toujours être évitées.
À éviter
components/
|- SdSettings.vue
|- UProfOpts.vue
OK
components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
La casse des noms de prop
Les noms de prop doivent toujours utiliser camelCase lors des déclarations. Lorsqu'elles sont utilisées dans des template du DOM, les props doivent être écrites en kebab-case. Les templates des composants monofichiers et JSX peuvent utiliser des props en kebab-case ou en camelCase. La casse doit être cohérente - si vous choisissez d'utiliser des props en camelCase, assurez-vous de ne pas utiliser la casse kebab-case ailleurs dans votre application.
À éviter
js
const props = defineProps({
'greeting-text': String
})
template
// for in-DOM templates
<welcome-message greetingText="hi"></welcome-message>
OK
js
const props = defineProps({
greetingText: String
})
template
// pour les SFC - assurez-vous que la casse est cohérente tout au long du projet
// vous pouvez utiliser l'une ou l'autre des conventions, mais nous vous déconseillons de mélanger deux styles de casse différents
<WelcomeMessage greeting-text="hi"/>
// ou
<WelcomeMessage greetingText="hi"/>
template
// pour les template du DOM
<welcome-message greeting-text="hi"></welcome-message>
Éléments à attributs multiples
Les éléments avec plusieurs attributs doivent s'étendre sur plusieurs lignes, avec un attribut par ligne.
En JavaScript, étendre des objets avec plusieurs propriétés sur plusieurs lignes est largement considéré comme une bonne convention, car ils sont beaucoup plus faciles à lire. Les templates et JSX méritent la même considération.
À éviter
template
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
template
<MyComponent foo="a" bar="b" baz="c"/>
OK
template
<img
src="https://vuejs.org/images/logo.png"
alt="Vue Logo"
>
template
<MyComponent
foo="a"
bar="b"
baz="c"
/>
Expressions simples dans les templates
Les templates de composants ne doivent inclure que des expressions simples, avec des expressions plus complexes refactorisées en propriétés calculées ou en méthodes.
Les expressions complexes dans vos templates les rendent moins déclaratifs. Nous devons nous efforcer de décrire ce qui devrait apparaître, et non comment nous calculons cette valeur. Les propriétés calculées et les méthodes permettent également de réutiliser le code.
À éviter
template
{{
fullName.split(' ').map((word) => {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
OK
template
<!-- Dans un template -->
{{ normalizedFullName }}
js
// L'expression complexe a été déplacée vers une propriété calculée
const normalizedFullName = computed(() =>
fullName.value
.split(' ')
.map((word) => word[0].toUpperCase() + word.slice(1))
.join(' ')
)
Propriétés calculées simples
Les propriétés calculées complexes doivent être divisées en propriétés plus simples.
Explications détaillées
Les propriétés calculées plus simples et bien nommées sont :
Plus faciles à tester
Lorsque chaque propriété calculée ne contient qu'une expression très simple, avec très peu de dépendances, il est beaucoup plus facile d'écrire des tests qui vérifient leur bon fonctionnement.
Plus faciles à lire
Simplifier les propriétés calculées vous oblige à donner à chaque valeur un nom descriptif, même si elle n'est pas réutilisée. Cela permet aux autres développeurs (et à vous-même) de se concentrer beaucoup plus facilement sur le code qui leur tient à cœur et de comprendre ce qui se passe.
Plus adaptables à l'évolution des besoins
Toute valeur pouvant être nommée peut être utile pour la vue. Par exemple, nous pourrions décider d'afficher un message indiquant à l'utilisateur combien d'argent il a économisé. Nous pourrions également décider de calculer la taxe de vente, mais peut-être l'afficher séparément, plutôt que dans le cadre du prix final.
Les propriétés calculées simples et ciblées font réduire le nombre d'hypothèses sur la façon dont les informations seront utilisées, elles nécessitent donc moins de refactoring à mesure que les exigences changent.
À éviter
js
const price = computed(() => {
const basePrice = manufactureCost.value / (1 - profitMargin.value)
return basePrice - basePrice * (discountPercent.value || 0)
})
OK
js
const basePrice = computed(
() => manufactureCost.value / (1 - profitMargin.value)
)
const discount = computed(
() => basePrice.value * (discountPercent.value || 0)
)
const finalPrice = computed(() => basePrice.value - discount.value)
Les valeurs des attributs entres guillemets
Les valeurs des attributs HTML non-vide doivent toujours être entre des guillemets (simple (' ') ou double (" "), celui qui n'est pas utilisé dans votre JS).
Bien que les valeurs d'attribut sans espace ne soient pas obligées d'avoir des guillemets en HTML, cette pratique conduit souvent à éviter les espaces, ce qui rend les valeurs d'attribut moins lisibles.
À éviter
template
<input type=text>
template
<AppSidebar :style={width:sidebarWidth+'px'}>
OK
template
<input type="text">
template
<AppSidebar :style="{ width: sidebarWidth + 'px' }">
Les raccourcis de directives
Les raccourcis de directives (:
pour v-bind:
, @
pour v-on:
et #
pour v-slot
) doivent toujours être utilisés ou ne jamais l'être.
À éviter
template
<input
v-bind:value="newTodoText"
:placeholder="newTodoInstructions"
>
template
<input
v-on:input="onInput"
@focus="onFocus"
>
template
<template v-slot:header>
<h1>Ceci est le titre de la page</h1>
</template>
<template #footer>
<p>Ici quelques infos contacts</p>
</template>
OK
template
<input
:value="newTodoText"
:placeholder="newTodoInstructions"
>
template
<input
v-bind:value="newTodoText"
v-bind:placeholder="newTodoInstructions"
>
template
<input
@input="onInput"
@focus="onFocus"
>
template
<input
v-on:input="onInput"
v-on:focus="onFocus"
>
template
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
template
<template #header>
<h1>Here might be a page title</h1>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>