`. Il contient toutes les informations dont nous avons besoin pour créer l'élément réel. Il contient également d'autres vnodes enfants, ce qui en fait la racine d'un arbre du DOM virtuel.
Un moteur d'exécution peut parcourir un arbre du DOM virtuel et construire un arbre du DOM réel à partir de celui-ci. Ce processus est appelé le **montage**.
Si nous avons deux copies d'arbres du DOM virtuel, le moteur de rendu peut également parcourir et comparer les deux arbres, en déterminant les différences, et appliquer ces changements au DOM réel. Ce processus est appelé **patch**, également connu sous le nom de "diffing" ou "réconciliation".
Le principal avantage du DOM virtuel est qu'il donne au développeur la possibilité de créer, inspecter et composer de manière programmatique les structures d'interface utilisateur souhaitées de façon déclarative, tout en laissant la manipulation directe du DOM au moteur de rendu.
## Pipeline de rendu {#render-pipeline}
Au niveau le plus élevé, voici ce qui se passe lorsqu'un composant Vue est monté :
1. **Compilation** : Les templates Vue sont compilés en **fonctions de rendu** : fonctions qui retournent des arbres du DOM virtuel. Cette étape peut être effectuée soit à l'avance via un outil de build, soit à la volée en utilisant le compilateur d'exécution.
2. **Montage** : Le moteur d'exécution invoque les fonctions de rendu, parcourt l'arbre du DOM virtuel retourné et crée des nœuds DOM réels en fonction. Cette étape est réalisée comme un [effet réactif](./reactivity-in-depth), et garde donc la trace de toutes les dépendances réactives qui ont été utilisées.
3. **Correction** (Patch) : Quand une dépendance utilisée pendant le montage change, l'effet est ré-exécuté. Cette fois, un nouvel arbre du DOM virtuel mis à jour est créé. Le moteur d'exécution parcourt le nouvel arbre, le compare avec l'ancien et applique les mises à jour nécessaires au DOM réel.

## Templates vs. Fonctions de rendu {#templates-vs-render-functions}
Les templates Vue sont compilés en fonctions de rendu du DOM virtuel. Vue fournit également des API qui nous permettent de sauter l'étape de compilation des templates et de créer directement des fonctions de rendu. Celles-ci sont plus flexibles que les templates pour incorporer des logiques très dynamiques, car vous pouvez travailler avec les vnodes en utilisant toute la puissance de JavaScript.
Dans ce cas, pourquoi Vue recommande-t-il les templates par défaut ? Il y a un plusieurs raisons :
1. Les templates se rapprochent du HTML réel. Il est donc plus facile de réutiliser des extraits HTML existants, d'appliquer les meilleures pratiques en matière d'accessibilité, de créer un style avec du CSS, et pour les designers de comprendre le code et de le modifier.
2. Les templates sont plus faciles à analyser statiquement en raison de leur syntaxe plus déterministe. Cela permet au compilateur de templates de Vue d'appliquer de nombreuses optimisations au moment de la compilation afin d'améliorer les performances du DOM virtuel (que nous aborderons plus loin).
En pratique, les templates sont suffisants pour la plupart des cas d'utilisation d'une application. Les fonctions de rendu ne sont généralement utilisées que dans les composants réutilisables qui doivent gérer une logique de rendu hautement dynamique. L'utilisation des fonctions de rendu est abordée plus en détail dans [Fonctions de rendu et JSX](./render-function).
## DOM virtuel basé sur la compilation {#compiler-informed-virtual-dom}
L'implémentation du DOM virtuel dans React et la plupart de ses autres implémentations sont purement basées sur l'exécution : l'algorithme de réconciliation ne peut pas faire d'hypothèses sur l'arbre du DOM virtuel entrant, il doit donc traverser entièrement l'arbre et différencier les props de chaque vnode afin d'assurer la correction. En outre, même si une partie de l'arbre ne change jamais, de nouveaux vnodes sont toujours créés pour eux à chaque nouveau rendu, ce qui entraîne une charge mémoire inutile. C'est l'un des aspects les plus critiqués du DOM virtuel : le processus de réconciliation quelque peu brutal sacrifie l'efficacité au profit de la déclarativité et de l'exactitude.
Cependant d'autres façons de faire existent. Dans Vue, le framework a le contrôle à la fois pendant la compilation et l'exécution. Cela nous permet de mettre en œuvre de nombreuses optimisations au moment de la compilation dont seul un moteur de rendu étroitement intégré peut tirer parti. Le compilateur peut analyser statiquement le template et laisser des indications dans le code généré afin que le moteur d'exécution puisse gagner du temps lorsque cela est possible. Dans le même temps, l'utilisateur peut toujours avoir le contrôle jusqu'à la fonction de rendu pour agir de manière plus directe lorsque cela est nécessaire. Nous appelons cette approche hybride le **DOM virtuel basé sur la compilation**.
Nous aborderons ci-dessous quelques optimisations importantes réalisées par le compilateur de templates Vue dans le but d'améliorer les performances d'exécution du DOM virtuel.
### Cache Statique {#cache-static}
Il arrive régulièrement que certaines parties d'un template ne contiennent pas de liaisons dynamiques :
```vue-html{2-3}
```
[Inspection dans l'explorateur de template](https://template-explorer.vuejs.org/#eyJzcmMiOiI8ZGl2PlxuICA8ZGl2PmZvbzwvZGl2PiA8IS0tIGNhY2hlZCAtLT5cbiAgPGRpdj5iYXI8L2Rpdj4gPCEtLSBjYWNoZWQgLS0+XG4gIDxkaXY+e3sgZHluYW1pYyB9fTwvZGl2PlxuPC9kaXY+XG4iLCJvcHRpb25zIjp7ImhvaXN0U3RhdGljIjp0cnVlfX0=)
Les divs `foo` et `bar` sont statiques - recréer des vnodes et les différencier à chaque rendu est inutile. Le moteur de rendu crée ces vnodes lors du rendu initial, les met en cache et réutilise les mêmes vnodes lors de chaque rendu ultérieur. Le moteur de rendu est également capable de ne pas les différencier quand il remarque que l'ancien et le nouveau vnode sont les mêmes.
En outre, lorsqu'il y a suffisamment d'éléments statiques consécutifs, ils seront condensés en un seul "vnode statique" qui contient une simple chaîne de caractères HTML pour tous ces nœuds ([Exemple](https://template-explorer.vuejs.org/#eyJzcmMiOiI8ZGl2PlxuICA8ZGl2IGNsYXNzPVwiZm9vXCI+Zm9vPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJmb29cIj5mb288L2Rpdj5cbiAgPGRpdiBjbGFzcz1cImZvb1wiPmZvbzwvZGl2PlxuICA8ZGl2IGNsYXNzPVwiZm9vXCI+Zm9vPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJmb29cIj5mb288L2Rpdj5cbiAgPGRpdj57eyBkeW5hbWljIH19PC9kaXY+XG48L2Rpdj4iLCJzc3IiOmZhbHNlLCJvcHRpb25zIjp7ImhvaXN0U3RhdGljIjp0cnVlfX0=)). Ces vnodes statiques sont montés en modifiant directement `innerHTML`.
### Marques de correction {#patch-flags}
Nous pouvons également déduire de nombreuses informations concernant un élément unique possédant des liaisons dynamiques au moment de la compilation :
```vue-html
{{ dynamic }}
```
[Inspection dans l'explorateur de template](https://template-explorer.vuejs.org/#eyJzcmMiOiI8ZGl2IDpjbGFzcz1cInsgYWN0aXZlIH1cIj48L2Rpdj5cblxuPGlucHV0IDppZD1cImlkXCIgOnZhbHVlPVwidmFsdWVcIj5cblxuPGRpdj57eyBkeW5hbWljIH19PC9kaXY+Iiwib3B0aW9ucyI6e319)
Lors de la génération du code de la fonction de rendu pour ces éléments, Vue encode le type de mise à jour dont chacun d'entre eux a besoin directement dans l'appel de création de vnode :
```js{3}
createElementVNode("div", {
class: _normalizeClass({ active: _ctx.active })
}, null, 2 /* CLASS */)
```
Le dernier argument, `2`, est une [option de correction](https://github.com/vuejs/core/blob/main/packages/shared/src/patchFlags.ts). Un élément peut avoir plusieurs marques de correction, qui seront fusionnées en un seul nombre. Le moteur d'exécution peut alors vérifier les marques en utilisant des [opérations sur les bits](https://en.wikipedia.org/wiki/Bitwise_operation) pour déterminer s'il doit effectuer certaines opération :
```js
if (vnode.patchFlag & PatchFlags.CLASS /* 2 */) {
// met à jour la classe de l'élément
}
```
Les vérifications par bit sont extrêmement rapides. Grâce aux marques de correction, Vue est en mesure d'effectuer le moins d'opérations possible lors de la mise à jour des éléments avec des liaisons dynamiques.
Vue encode également le type des enfants d'un vnode. Par exemple, un template qui possède plusieurs nœuds racines est représenté comme un fragment. Dans la plupart des cas, nous savons avec certitude que l'ordre de ces nœuds racines ne changera jamais, de sorte que cette information peut également être fournie au moment de l'exécution en tant qu'indicateur de patch :
```js{4}
export function render() {
return (_openBlock(), _createElementBlock(_Fragment, null, [
/* enfants */
], 64 /* STABLE_FRAGMENT */))
}
```
Lors de l'exécution, la réconciliation de l'ordre des enfants pour le fragment racine peut donc être totalement ignorée.
### Réduction d'un arbre {#tree-flattening}
Si vous regardez à nouveau le code généré dans l'exemple précédent, vous remarquerez que la racine de l'arbre du DOM virtuel retourné est créée en utilisant un appel spécial à `createElementBlock()` :
```js{2}
export function render() {
return (_openBlock(), _createElementBlock(_Fragment, null, [
/* enfants */
], 64 /* STABLE_FRAGMENT */))
}
```
Conceptuellement, un "bloc" est une partie du template qui a une structure interne stable. Dans notre cas, le modèle template n'a qu'un seul bloc car il ne contient pas de directives structurelles comme `v-if` et `v-for`.
Chaque bloc traque tous les nœuds descendants (pas seulement les enfants directs) possédant des marques de correction. Par exemple :
```vue-html{3,5}
```
Il en résulte un tableau réduit qui ne contient que les nœuds descendants dynamiques :
```
div (block root)
- div with :id binding
- div with {{ bar }} binding
```
Lorsque ce composant doit effectuer un nouveau rendu, il ne doit parcourir que l'arbre réduit au lieu de l'arbre complet. C'est ce qu'on appelle la réduction de l'arbre (**Tree Flattening**), et cela réduit considérablement le nombre de nœuds qui doivent être traversés pendant la réconciliation virtuelle du DOM. Toutes les parties statiques du template sont ignorées.
Les directives `v-if` et `v-for` vont créer de nouveaux nœuds pour un bloc :
```vue-html
```
Un bloc enfant est traqué à l'intérieur du tableau des descendants dynamiques du bloc parent. Cela permet au bloc parent de conserver une structure stable.
### Conséquences sur l'hydratation SSR {#impact-on-ssr-hydration}
Les marques de correction et la réduction des arbres améliorent également considérablement les performances de Vue en matière d'[hydratation SSR](/guide/scaling-up/ssr#client-hydration) :
* L'hydratation d'un seul élément peut utiliser des chemins rapides basés sur les marques de correction du vnode correspondant.
* Seuls les nœuds de bloc et leurs descendants dynamiques doivent être parcourus pendant l'hydratation, ce qui permet d'obtenir une hydratation partielle au niveau du template.
---
---
url: /ecosystem/newsletters.md
---
# Newsletters de la communauté {#community-newsletters}
Il existe de nombreuses newsletters et de nombreux blogs de la communauté consacrés à Vue qui vous informent des dernières nouvelles et des événements survenus dans l'écosystème Vue. Voici une liste non exhaustive de celles et ceux qui sont actifs et sur lesquels nous sommes tombés :
* [Vue.js Feed](https://vuejsfeed.com/)
* [Michael Thiessen](https://michaelnthiessen.com/newsletter)
* [Jakub Andrzejewski](https://dev.to/jacobandrewsky)
* [Weekly Vue News](https://weekly-vue.news/)
* [Vue.js Developers Newsletter](https://vuejsdevelopers.com/newsletter/)
Si vous en connaissez une newsletter ou un blog qui n'est pas encore inclus, veuillez soumettre une pull request en utilisant le lien ci-dessous !
---
---
url: /guide/essentials/watchers.md
---
# Observateurs {#watchers}
## Exemple Basique {#basic-example}
Les propriétés calculées nous permettent de calculer des valeurs dérivées de manière déclarative. Toutefois, il y a des cas dans lesquels nous devons réaliser des "effets de bord" en réaction aux changements de l'état - par exemple, muter le DOM, ou changer une autre partie de l'état en fonction du résultat d'une opération asynchrone.
Avec l'Options API, on peut utiliser l'[option `watch`](/api/options-state#watch) pour déclencher une fonction chaque fois qu'une propriété réactive change :
```js
export default {
data() {
return {
question: '',
answer: 'Questions usually contain a question mark. ;-)',
loading: false
}
},
watch: {
// à chaque fois que question change, cette fonction sera exécutée
question(newQuestion) {
if (newQuestion.includes('?')) {
this.getAnswer()
}
}
},
methods: {
async getAnswer() {
this.loading = true
this.answer = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
this.answer = (await res.json()).answer
} catch (error) {
this.answer = 'Error! Could not reach the API. ' + error
} finally {
this.loading = false
}
}
}
}
```
```vue-html
Ask a yes/no question:
{{ answer }}
```
[Essayer en ligne](https://play.vuejs.org/#eNp9VE1v2zAM/SucLnaw1D70lqUbsiKH7rB1W4++aDYdq5ElTx9xgiD/fbT8lXZFAQO2+Mgn8pH0mW2aJjl4ZCu2trkRjfucKTw22jgosOReOjhnCqDgjseL/hvAoPNGjSeAvx6tE1qtIIqWo5Er26Ih088BteCt51KeINfKcaGAT5FQc7NP4NPNYiaQmhdC7VZQcmlxMF+61yUcWu7yajVmkabQVqjwgGZmzSuudmiX4CphofQqD+ZWSAnGqz5y9I4VtmOuS9CyGA9T3QCihGu3RKhc+gJtHH2JFld+EG5Mdug2QYZ4MSKhgBd11OgqXdipEm5PKoer0Jk2kA66wB044/EF1GtOSPRUCbUnryRJosnFnK4zpC5YR7205M9bLhyUSIrGUeVcY1dpekKrdNK6MuWNiKYKXt8V98FElDxbknGxGLCpZMi7VkGMxmjzv0pz1tvO4QPcay8LULoj5RToKoTN40MCEXyEQDJTl0KFmXpNOqsUxudN+TNFzzqdJp8ODutGcod0Alg34QWwsXsaVtIjVXqe9h5bC9V4B4ebWhco7zI24hmDVSEs/yOxIPOQEFnTnjzt2emS83nYFrhcevM6nRJhS+Ys9aoUu6Av7WqoNWO5rhsh0fxownplbBqhjJEmuv0WbN2UDNtDMRXm+zfsz/bY2TL2SH1Ec8CMTZjjhqaxh7e/v+ORvieQqvaSvN8Bf6HV0veSdG5fvSoo7Su/kO1D3f13SKInuz06VHYsahzzfl0yRj+s+3dKn9O9TW7HPrPLP624lFU=)
L'option `watch` supporte également comme clé un chemin délimité par des points :
```js
export default {
watch: {
// Remarque : seulement des chemins simples. Les expressions ne sont pas supportées.
'some.nested.key'(newValue) {
// ...
}
}
}
```
Avec la Composition API, nous pouvons utiliser la [fonction `watch`](/api/reactivity-core#watch) pour déclencher une fonction de rappel chaque fois qu'une partie d'un état réactif change :
```vue
Ask a yes/no question:
{{ answer }}
```
[Essayer en ligne](https://play.vuejs.org/#eNp9U8Fy0zAQ/ZVFF9tDah96C2mZ0umhHKBAj7oIe52oUSQjyXEyGf87KytyoDC9JPa+p+e3b1cndtd15b5HtmQrV1vZeXDo++6Wa7nrjPVwAovtAgbh6w2M0Fqzg4xOZFxzXRvtPPzq0XlpNNwEbp5lRUKEdgPaVP925jnoXS+UOgKxvJAaxEVjJ+y2hA9XxUVFGdFIvT7LtEI5JIzrqjrbGozdOmikxdqTKqmIQOV6gvOkvQDhjrqGXOOQvCzAqCa9FHBzCyeuAWT7F6uUulZ9gy7PPmZFETmQjJV7oXoke972GJHY+Axkzxupt4FalhRcYHh7TDIQcqA+LTriikFIDy0G59nG+84tq+qITpty8G0lOhmSiedefSaPZ0mnfHFG50VRRkbkj1BPceVorbFzF/+6fQj4O7g3vWpAm6Ao6JzfINw9PZaQwXuYNJJuK/U0z1nxdTLT0M7s8Ec/I3WxquLS0brRi8ddp4RHegNYhR0M/Du3pXFSAJU285osI7aSuus97K92pkF1w1nCOYNlI534qbCh8tkOVasoXkV1+sjplLZ0HGN5Vc1G2IJ5R8Np5XpKlK7J1CJntdl1UqH92k0bzdkyNc8ZRWGGz1MtbMQi1esN1tv/1F/cIdQ4e6LJod0jZzPmhV2jj/DDjy94oOcZpK57Rew3wO/ojOpjJIH2qdcN2f6DN7l9nC47RfTsHg4etUtNpZUeJz5ndPPv32j9Yve6vE6DZuNvu1R2Tg==)
### Les types de sources de watch {#watch-source-types}
Le premier argument de `watch` peut être différents types de "sources" réactives : ça peut être une ref (y compris des refs calculées), un objet réactif, une fonction [accesseur](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description), ou un tableau de différentes sources :
```js
const x = ref(0)
const y = ref(0)
// simple ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// accesseur
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// tableau de différentes sources
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})
```
Notez que vous ne pouvez pas observer une propriété d'un objet réactif de cette manière :
```js
const obj = reactive({ count: 0 })
// cela ne fonctionnera pas car on passe un nombre à watch()
watch(obj.count, (count) => {
console.log(`Count est égal à: ${count}`)
})
```
À la place, utilisez un accesseur :
```js
// à la place, utilisez un accesseur :
watch(
() => obj.count,
(count) => {
console.log(`Count est égal à: ${count}`)
}
)
```
## Observateurs profonds {#deep-watchers}
`watch` est par défaut superficiel : la fonction de rappel ne sera déclenchée que lorsque la propriété observée se verra assigner une nouvelle valeur - elle ne sera pas déclenchée lors du changement d'une propriété imbriquée. Si vous voulez que la fonction de rappel s'exécute à chaque mutation imbriquée, vous devez utiliser un observateur profond :
```js
export default {
watch: {
someObject: {
handler(newValue, oldValue) {
// Remarque: `newValue` sera égale à `oldValue` ici
// à chaque mutation imbriquée tant que l'objet lui-même
// n'a pas été remplacé.
},
deep: true
}
}
}
```
Lorsque vous appelez `watch()` directement sur un objet réactif, un observateur profond va implicitement être créé - la fonction de rappel sera déclenchée à chaque mutation imbriquée :
```js
const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
// exécution à chaque mutation d'une propriété imbriquée
// Remarque : `newValue` sera égale à `oldValue` ici
// car elles pointent toutes les deux sur le même objet !
})
obj.count++
```
Il ne faut pas confondre avec un accesseur qui retourne un objet réactif - dans ce dernier cas, la fonction de rappel ne sera exécutée que si l'accesseur retourne un objet différent :
```js
watch(
() => state.someObject,
() => {
// exécution seulement lorsque state.someObject est remplacé
}
)
```
Toutefois, vous pouvez transformer ce second cas en un observateur profond en utilisant explicitement l'option `deep` :
```js
watch(
() => state.someObject,
(newValue, oldValue) => {
// Remarque : `newValue` sera égale à `oldValue` ici
// *sauf si* state.someObject a été remplacé
},
{ deep: true }
)
```
À partir de la version 3.5, l'option `deep` peut aussi être un nombre indiquant la profondeur maximale à traverser, c'est-à-dire de combien de niveaux Vue traverse un objet avec des propriétés imbriquées.
:::warning À utiliser avec précaution
Les observateurs profonds nécessitent de traverser toutes les propriétés imbriquées de l'objet observé, et peuvent être consommateurs de ressources lorsqu'ils sont utilisés sur des structures importantes de données. Utilisez-les seulement si nécessaire, en ayant conscience des implications en matière de performances.
:::
## Les observateurs impatients {#eager-watchers}
`watch` fonctionne à la volée par défaut : la fonction de rappel ne sera pas appelée tant que la source observée n'aura pas changé. Mais dans certains cas, on peut souhaiter que cette même logique de rappel soit exécutée de manière précoce - par exemple, on peut vouloir récupérer des données initiales, puis les récupérer de nouveau chaque fois qu'un état pertinent change.
Nous pouvons forcer la fonction de rappel d'un observateur à être exécutée immédiatement en la déclarant via un objet avec une fonction de gestion et l'option `immediate: true` :
```js
export default {
// ...
watch: {
question: {
handler(newQuestion) {
// cela sera exécuté immédiatement à la création du composant
},
// force l'exécution précoce de la fonction de rappel
immediate: true
}
}
// ...
}
```
L'exécution initiale d'une fonction de gestion aura lieu juste avant le hook `created`. Vue aura déjà traité les options `data`, `computed`, et `méthodes`, donc ces propriétés seront disponibles à la première invocation.
Nous pouvons forcer l'exécution immédiate d'un observateur en passant l'option `immediate: true` :
```js
watch(
source,
(newValue, oldValue) => {
// execution immédiate, puis à chaque fois que `source` change
},
{ immediate: true }
)
```
## Observateurs unitaires {#once-watchers}
* Supporté à partir de la version 3.4
La fonction de rappel de l'observateur sera exécutée dès lors qu'une source observée change. Si vous voulez que la fonction de rappel soit déclenchée une seule fois quand il y a un changement, utilisez l'option `once: true`.
```js
export default {
watch: {
source: {
handler(newValue, oldValue) {
// quand `source` change, déclenchée une seule fois
},
once: true
}
}
}
```
```js
watch(
source,
(newValue, oldValue) => {
// quand `source` change, déclenchée une seule fois
},
{ once: true }
)
```
## `watchEffect()` \*\* {#watcheffect}
Il est commun pour la fonction de l'observateur d'utiliser exactement le même état réactif comme source. Par exemple, considérez le code suivant, qui utilise un observateur pour charger une ressource distante à chaque changement de la ref `todoId` :
```js
const todoId = ref(1)
const data = ref(null)
watch(
todoId,
async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
},
{ immediate: true }
)
```
En particulier, remarquez comment l'observateur utilise doublement `todoId`, une fois comme source, ensuite à nouveau à l'intérieur de la fonction.
Cela peut être simplifié par [`watchEffect()`](/api/reactivity-core#watcheffect). `watchEffect()` nous permet d'effectuer des effets de bord immédiatement tout en traquant automatiquement les dépendances réactives de cet effet. L'exemple précédent peut être réécrit de la sorte :
```js
watchEffect(async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})
```
Ici, la fonction sera exécutée immédiatement, il n'y a pas besoin de spécifier `immediate : true`. Pendant son exécution, elle suivra automatiquement `todoId.value` comme une dépendance (similaire aux propriétés calculées). Chaque fois que `todoId.value` change, la fonction sera exécutée à nouveau. Avec `watchEffect()`, nous n'avons plus besoin de passer explicitement `todoId` comme source.
Vous pouvez vous référer à [cet exemple](/examples/#fetching-data) avec `watchEffect` et une récupération de données en action.
Pour des exemples comme ceux-ci, avec une seule dépendance, le bénéfice de `watchEffect()` est relativement faible. Mais pour les surveillances qui ont plusieurs dépendances, l'utilisation de `watchEffect()` supprime la charge de maintenir la liste des dépendances manuellement. De plus, si vous devez surveiller plusieurs propriétés dans une structure de données imbriquée, `watchEffect()` peut s'avérer plus efficace qu'un observateur profond, car il ne suivra que les propriétés qui sont utilisées dans la fonction, plutôt que de les suivre toutes de manière récursive.
:::tip
`watchEffect` traque les dépendances seulement pendant son exécution **synchrone**. Lorsque vous l'utilisez avec un rappel asynchrone, seules les propriétés accédées avant le premier événement `await` seront traquées.
:::
### `watch` vs. `watchEffect` {#watch-vs-watcheffect}
`watch` et `watchEffect` permettent tous les deux de réaliser des effets de bord. Leur principale différence réside dans la manière dont ils traquent leurs dépendances réactives :
* `watch` traque seulement la source explicitement observée . De plus, le rappel n'est déclenché que lorsque la source a bien changé. `watch` sépare la traque des dépendances et les effets de bord, ce qui nous donne plus de contrôle sur le moment où le rappel doit être exécuté.
* `watchEffect`, d'un autre côté, combine la traque des dépendances et les effets de bord en une phase. Il traque automatiquement chaque propriété réactive accédée durant son exécution synchrone. Cela est plus pratique et rend généralement le code plus concis, mais rend les dépendances réactives moins explicites.
## Nettoyage des effets de bord {#side-effect-cleanup}
Parfois, nous pouvons effectuer des effets secondaires, par exemple des requêtes asynchrones, dans un observateur :
```js
watch(id, (newId) => {
fetch(`/api/${newId}`).then(() => {
// logique de rappel
})
})
```
```js
export default {
watch: {
id(newId) {
fetch(`/api/${newId}`).then(() => {
// logique de rappel
})
}
}
}
```
Mais que se passe-t-il si `id` change avant que la requête ne soit terminée ? Lorsque la requête précédente se termine, elle déclenche toujours le callback avec une valeur d'ID qui est déjà périmée. Idéalement, nous voulons pouvoir annuler la requête périmée lorsque `id` change pour une nouvelle valeur.
Nous pouvons utiliser l'API [`onWatcherCleanup()`](/api/reactivity-core#onwatchercleanup) pour enregistrer une fonction de nettoyage qui sera appelée lorsque l'observateur est invalidé et sur le point d'être réexécuté :
```js {10-13}
import { watch, onWatcherCleanup } from 'vue'
watch(id, (newId) => {
const controller = new AbortController()
fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
// logique de rappel
})
onWatcherCleanup(() => {
// annuler la demande périmée
controller.abort()
})
})
```
```js {12-15}
import { onWatcherCleanup } from 'vue'
export default {
watch: {
id(newId) {
const controller = new AbortController()
fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
// logique de rappel
})
onWatcherCleanup(() => {
// annuler la demande périmée
controller.abort()
})
}
}
}
```
Notez que `onWatcherCleanup` n'est supporté que dans Vue 3.5+ et doit être appelé pendant l'exécution synchrone d'une fonction d'effet `watchEffect` ou d'une fonction de callback `watch` : vous ne pouvez pas l'appeler après une instruction `await` dans une fonction asynchrone.
Alternativement, une fonction `onCleanup` est également transmise aux callbacks des observateurs en tant que troisième argument, et à la fonction d'effet `watchEffect` en tant que premier argument:
```js
watch(id, (newId, oldId, onCleanup) => {
// ...
onCleanup(() => {
// logique de rappel
})
})
watchEffect((onCleanup) => {
// ...
onCleanup(() => {
// logique de rappel
})
})
```
```js
export default {
watch: {
id(newId, oldId, onCleanup) {
// ...
onCleanup(() => {
// logique de rappel
})
}
}
}
```
La fonction `onCleanup` transmise via l'argument de fonction est liée à l'instance de l'observateur, elle n'est donc pas soumise à la contrainte synchrone de `onWatcherCleanup`.
## Timing de nettoyage des rappels {#callback-flush-timing}
Lorsque vous mutez un état réactif, cela peut déclencher à la fois la mise à jour des composants Vue et des rappels d'observateur que vous avez créés.
Comme pour les mises à jour de composants, les rappels de l'observateur créés par l'utilisateur sont regroupés afin d'éviter les invocations en double. Par exemple, nous ne voulons probablement pas qu'un observateur se déclenche mille fois si nous introduisons de manière synchrone mille éléments dans un tableau observé.
Par défaut, le rappel d'un observateur est appelé **après** les mises à jour du composant parent (le cas échéant), et **avant** les mises à jour du DOM du composant propriétaire. Cela signifie que si vous tentez d'accéder au DOM du composant propriétaire à l'intérieur d'un callback de l'observateur, le DOM sera dans un état de pré-mise à jour.
### Observateurs a posteriori {#post-watchers}
Si vous voulez accéder au DOM **après** que Vue l'ait mis à jour, vous devez spécifier l'option `flush: 'post'` :
```js{6}
export default {
// ...
watch: {
key: {
handler() {},
flush: 'post'
}
}
}
```
```js{2,6}
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post'
})
```
Le `watchEffect()` "post-flush" a également un pseudonyme de confort, `watchPostEffect()`:
```js
import { watchPostEffect } from 'vue'
watchPostEffect(() => {
/* exécution après la mise à jour de Vue */
})
```
### Observateurs synchrones {#sync-watchers}
Il est également possible de créer un observateur qui se déclenche de manière synchrone, avant toute mise à jour gérée par Vue.
```js{6}
export default {
// ...
watch: {
key: {
handler() {},
flush: 'sync'
}
}
}
```
```js{2,6}
watch(source, callback, {
flush: 'sync'
})
watchEffect(callback, {
flush: 'sync'
})
```
Sync `watchEffect()` a également un alias de commodité, `watchSyncEffect()` :
```js
import { watchSyncEffect } from 'vue'
watchSyncEffect(() => {
/* exécuté de manière synchrone lors d'une modification réactive des données */
})
```
:::warning A utiliser avec précaution
Les observateurs synchrones n'ont pas de fonction de mise en lot et se déclenchent à chaque fois qu'une mutation réactive est détectée. Il est possible de les utiliser pour surveiller de simples valeurs booléennes, mais il faut éviter de les utiliser sur des sources de données qui peuvent être mutées plusieurs fois de manière synchrone, par exemple des tableaux.
:::
## `this.$watch()` \* {#this-watch}
Il est également possible de créer des observateurs de manière impérative en utilisant [la méthode d'instance `$watch()`](/api/component-instance#watch):
```js
export default {
created() {
this.$watch('question', (newQuestion) => {
// ...
})
}
}
```
Cela est utile lorsque vous avez besoin de paramétrer un observateur de manière conditionnelle, ou de seulement observer quelque chose en réponse à une interaction de l'utilisateur. Cela vous permet également d'arrêter l'observateur précocement.
## Arrêter un observateur {#stopping-a-watcher}
Les observateurs déclarés via l'option `watch` ou la méthode d'instance `$watch()` sont automatiquement arrêtés lorsque le composant propriétaire est démonté, donc dans la plupart des cas vous n'avez pas à vous soucier d'arrêter les observateurs vous-même.
Dans les rares cas où vous auriez besoin d'arrêter un observateur avant que le composant propriétaire ne soit démonté, l'API `$watch()` retourne une fonction permettant de le faire :
```js
const unwatch = this.$watch('foo', callback)
// ...lorsque l'observateur n'est plus nécessaire :
unwatch()
```
Les observateurs déclarés de manière synchrone à l'intérieur de `setup()` ou `
```
Pour arrêter manuellement un observateur, utilisez la fonction de gestion qu'il retourne. Cela fonctionne pour `watch` et pour `watchEffect`:
```js
const unwatch = watchEffect(() => {})
// ...plus tard, lorsqu'il n'est plus nécessaire
unwatch()
```
Notez que les cas où vous devriez être amenés à créer des observateurs de manière asynchrone sont rares, et une création synchrone devrait être choisie lorsque c'est possible. Si vous devez attendre des données asynchrones, vous pouvez intégrer votre logique d'observation dans une condition :
```js
// données à récupérer de manière asynchrone
const data = ref(null)
watchEffect(() => {
if (data.value) {
// on fait quelque chose lorsque les données sont chargées
}
})
```
---
---
url: /api/options-composition.md
---
# Options : Composition {#options-composition}
## provide {#provide}
Fournit des valeurs qui peuvent être injectées par les composants descendants.
* **Type :**
```ts
interface ComponentOptions {
provide?: object | ((this: ComponentPublicInstance) => object)
}
```
* **Détails**
`provide` et [`inject`](#inject) sont utilisées ensemble pour permettre à un composant ancêtre de servir d'injecteur de dépendances pour tous ses descendants, peu importe la profondeur de la hiérarchie des composants, tant qu'ils sont de la même lignée.
L'option `provide` doit être soit un objet, soit une fonction qui renvoie un objet. Cet objet contient les propriétés qui sont disponibles pour l'injection dans ses descendants. Vous pouvez utiliser des symboles comme clés dans cet objet.
* **Exemple**
Utilisation basique :
```js
const s = Symbol()
export default {
provide: {
foo: 'foo',
[s]: 'bar'
}
}
```
Utilisation d'une fonction pour fournir un état par composant :
```js
export default {
data() {
return {
msg: 'foo'
}
}
provide() {
return {
msg: this.msg
}
}
}
```
Notez que dans l'exemple ci-dessus, le `msg` fourni ne sera PAS réactif. Consultez [travailler avec la réactivité](/guide/components/provide-inject#working-with-reactivity) pour plus de détails.
* **Voir aussi** [Provide / Inject](/guide/components/provide-inject)
## inject {#inject}
Déclare les propriétés à injecter dans le composant actuel en les localisant à partir des fournisseurs ancêtres.
* **Type :**
```ts
interface ComponentOptions {
inject?: ArrayInjectOptions | ObjectInjectOptions
}
type ArrayInjectOptions = string[]
type ObjectInjectOptions = {
[key: string | symbol]:
| string
| symbol
| { from?: string | symbol; default?: any }
}
```
* **Détails**
L'option `inject` doit être soit :
* Un tableau de chaînes de caractères, ou
* Un objet où les clés sont le nom de la liaison locale et la valeur est soit :
* La clé (chaîne de caractères ou symbole) à rechercher dans les injections disponibles, ou bien
* Un objet où :
* La propriété `from` est la clé (chaîne de caractères ou symbole) à rechercher dans les injections disponibles, et
* La propriété `default` est utilisée comme valeur de secours. Comme pour les valeurs par défaut des props, une fonction *factory* est nécessaire pour les types objets afin d'éviter le partage de valeurs entre plusieurs instances de composants.
Une propriété injectée sera `undefined` si aucune propriété correspondante ou valeur par défaut n'a été fournie.
Notez que les liaisons injectées ne sont PAS réactives. Ceci est intentionnel. Cependant, si la valeur injectée est un objet réactif, les propriétés de cet objet restent réactives. Consultez [travailler avec la réactivité](/guide/components/provide-inject#working-with-reactivity) pour plus de détails.
* **Exemple**
Utilisation basique :
```js
export default {
inject: ['foo'],
created() {
console.log(this.foo)
}
}
```
En utilisant une valeur injectée comme valeur par défaut pour une prop :
```js
const Child = {
inject: ['foo'],
props: {
bar: {
default() {
return this.foo
}
}
}
}
```
En utilisant une valeur injectée comme entrée de données :
```js
const Child = {
inject: ['foo'],
data() {
return {
bar: this.foo
}
}
}
```
Les injections peuvent être optionnelles avec une valeur par défaut :
```js
const Child = {
inject: {
foo: { default: 'foo' }
}
}
```
Si l'injection doit se faire à partir d'une propriété portant un nom différent, utilisez `from` pour désigner la propriété source :
```js
const Child = {
inject: {
foo: {
from: 'bar',
default: 'foo'
}
}
}
```
Comme pour les valeurs par défaut des props, vous devez utiliser une fonction *factory* pour les valeurs non primitives :
```js
const Child = {
inject: {
foo: {
from: 'bar',
default: () => [1, 2, 3]
}
}
}
```
* **Voir aussi** [Provide / Inject](/guide/components/provide-inject)
## mixins {#mixins}
Un tableau d'objets d'options à introduire dans le composant actuel.
* **Type :**
```ts
interface ComponentOptions {
mixins?: ComponentOptions[]
}
```
* **Détails**
L'option `mixins` accepte un tableau d'objets mixins. Ces objets mixins peuvent contenir des options d'instance comme des objets d'instance normaux, et ils seront fusionnés avec les options éventuelles en utilisant la logique de fusion des options. Par exemple, si votre mixin contient un hook `created` et que le composant lui-même en possède un, les deux fonctions seront appelées.
Les hooks des mixins sont appelés dans l'ordre où ils sont fournis, et sont appelés avant les propres hooks du composant.
:::warning N'est plus recommandé
Avec Vue 2, les mixins étaient le principal mécanisme pour créer des morceaux réutilisables des logiques de composants. Bien que les mixins continuent d'être pris en charge avec Vue 3, la [Composition API](/guide/reusability/composables) est désormais l'approche privilégiée pour la réutilisation du code entre les composants.
:::
* **Exemple**
```js
const mixin = {
created() {
console.log(1)
}
}
createApp({
created() {
console.log(2)
},
mixins: [mixin]
})
// => 1
// => 2
```
## extends {#extends}
Un composant de la "classe de base" à partir duquel on peut étendre un composant.
* **Type :**
```ts
interface ComponentOptions {
extends?: ComponentOptions
}
```
* **Détails**
Permet à un composant d'en étendre un autre, en héritant de ses options de composant.
Du point de vue de l'implémentation, `extends` est presque identique à `mixins`. Le composant spécifié par `extends` sera traité comme s'il était le premier mixin.
Cependant, `extends` et `mixins` expriment des intentions différentes. L'option `mixins` est principalement utilisée pour composer des morceaux de fonctionnalité, alors que `extends` est principalement concerné par l'héritage.
Comme avec `mixins`, toutes les options (excepté pour `setup()`) seront fusionnées en utilisant la stratégie de fusion appropriée.
* **Exemple**
```js
const CompA = { ... }
const CompB = {
extends: CompA,
...
}
```
:::warning Non recommandé pour la Composition API
`extends` est conçu pour l'Options API et ne gère pas la fusion du hook `setup()`.
Avec la Composition API, le modèle mental préféré pour la réutilisation logique est la « composition » plutôt que « l'héritage ». Si vous avez besoin de réutiliser la logique d'un composant dans un autre, envisagez d'extraire ce qui est pertinent dans un [Composable](/guide/reusability/composables#composables).
Si vous avez toujours l'intention d'« étendre » un composant à l'aide de la Composition API, vous pouvez appeler le `setup()` du composant de base dans le `setup()` du composant d'extension :
```js
import Base from './Base.js'
export default {
extends: Base,
setup(props, ctx) {
return {
...Base.setup(props, ctx),
// liaisons locales
}
}
}
```
:::
---
---
url: /api/options-lifecycle.md
---
# Options : Cycle de vie {#options-lifecycle}
:::info Voir aussi
Pour en savoir plus sur l'utilisation partagée des hooks du cycle de vie, consultez [Guide - Les hooks du cycle de vie](/guide/essentials/lifecycle)
:::
## beforeCreate {#beforecreate}
Appelé lors de l'initialisation de l'instance.
* **Type :**
```ts
interface ComponentOptions {
beforeCreate?(this: ComponentPublicInstance): void
}
```
* **Détails**
Appelé immédiatement lorsque l'instance est initialisée, après la résolution des props.
Ensuite les props seront définies comme des propriétés réactives et les états comme `data()` ou `computed` seront configurés.
Notez que le hook `setup()` de la Composition API est appelé avant tous les hooks de l'Options API, même `beforeCreate()`.
## created {#created}
Appelé après que l'instance ait terminé de traiter toutes les options liées à l'état.
* **Type :**
```ts
interface ComponentOptions {
created?(this: ComponentPublicInstance): void
}
```
* **Détails**
Lorsque ce hook est appelé, les éléments suivants ont déjà été mis en place : données réactives, propriétés calculées, méthodes et observateurs. Cependant, la phase de montage n'a pas été lancée, et la propriété `$el` n'est encore disponible.
## beforeMount {#beforemount}
Appelé juste avant que le composant soit monté.
* **Type :**
```ts
interface ComponentOptions {
beforeMount?(this: ComponentPublicInstance): void
}
```
* **Détails**
Lorsque ce hook est appelé, le composant a fini de configurer son état réactif, mais aucun noeud du DOM n'a encore été créé. Il est sur le point d'exécuter son effet de rendu du DOM pour la première fois.
**Ce hook n'est pas appelé pendant le rendu côté serveur.**
## mounted {#mounted}
Appelé après que le composant ait été monté.
* **Type :**
```ts
interface ComponentOptions {
mounted?(this: ComponentPublicInstance): void
}
```
* **Détails**
Un composant est considéré comme monté après que :
* Tous ses composants enfants synchrones ont été montés (n'inclut pas les composants asynchrones ou les composants à l'intérieur des arbres `
`).
* Son propre arbre du DOM a été créé et inséré dans le conteneur parent. Notez que cela garantit que seulement l'arbre du DOM du composant est déjà placé dans le document, même si le conteneur racine de l'application y est.
Ce hook est généralement utilisé pour effectuer des effets de bord qui nécessitent un accès au DOM rendu du composant, ou pour limiter le code lié au DOM au client dans une [application rendue par le serveur](/guide/scaling-up/ssr).
**Ce hook n'est pas appelé pendant le rendu côté serveur.**
## beforeUpdate {#beforeupdate}
Appelé juste avant que le composant ne soit sur le point de mettre à jour son arbre du DOM après un changement d'état réactif.
* **Type :**
```ts
interface ComponentOptions {
beforeUpdate?(this: ComponentPublicInstance): void
}
```
* **Détails**
Ce hook peut être utilisé pour accéder à l'état du DOM avant que Vue ne le mette à jour. Il est également possible de modifier l'état d'un composant à l'intérieur de ce hook.
**Ce hook n'est pas appelé pendant le rendu côté serveur.**
## updated {#updated}
Appelé après que le composant ait mis à jour son arbre du DOM suite à un changement d'état réactif.
* **Type :**
```ts
interface ComponentOptions {
updated?(this: ComponentPublicInstance): void
}
```
* **Détails**
Le hook *updated* d'un composant parent est appelé après celui de ses composants enfants.
Ce hook est appelé après toute mise à jour du DOM du composant, laquelle peut être causée par différents changements d'état. Si vous devez accéder au DOM mis à jour après un changement d'état spécifique, utilisez plutôt [nextTick()](/api/general#nexttick).
**Ce hook n'est pas appelé pendant le rendu côté serveur.**
:::warning
Ne modifiez pas l'état du composant dans le hook *updated* - cela conduirait à une boucle de mises à jour infinie !
:::
## beforeUnmount {#beforeunmount}
Appelé juste avant que l'instance d'un composant ne soit démontée.
* **Type :**
```ts
interface ComponentOptions {
beforeUnmount?(this: ComponentPublicInstance): void
}
```
* **Détails**
Lorsque ce hook est appelé, l'instance du composant est toujours totalement fonctionnelle.
**Ce hook n'est pas appelé pendant le rendu côté serveur.**
## unmounted {#unmounted}
Appelé après que le composant ait été démonté.
* **Type :**
```ts
interface ComponentOptions {
unmounted?(this: ComponentPublicInstance): void
}
```
* **Détails**
Un composant est considéré comme démonté après que :
* Tous ses composants enfants ont été démontés.
* Tous ses effets réactifs associés (effet de rendu et propriétés calculées / observateurs créés pendant `setup()`) ont été arrêtés.
Utilisez ce hook pour nettoyer manuellement les effets de bord créés, tels que les minuteurs, les écouteurs d'événements du DOM ou les connexions au serveur.
**Ce hook n'est pas appelé pendant le rendu côté serveur.**
## errorCaptured {#errorcaptured}
Appelé lorsqu'une erreur venant d'un composant descendant a été capturée.
* **Type :**
```ts
interface ComponentOptions {
errorCaptured?(
this: ComponentPublicInstance,
err: unknown,
instance: ComponentPublicInstance | null,
info: string
): boolean | void
}
```
* **Détails**
Les erreurs peuvent être capturées à partir des sources suivantes :
* Rendu de composants
* Gestionnaires d'événements
* Hooks de cycle de vie
* Fonction `setup()`
* Observateurs
* Hooks de directives personnalisées
* Hooks de transition
Ce hook reçoit trois arguments : l'erreur, l'instance du composant qui a déclenché l'erreur, et une information sous forme de chaînes de caractères spécifiant le type de source de l'erreur.
:::tip
En production, le troisième argument (`info`) sera un code raccourci plutôt que toute la chaîne d'information. Vous pouvez trouver le code correspondant dans la [Référence des erreurs en production](/error-reference/#runtime-errors).
:::
Vous pouvez modifier l'état du composant dans `errorCaptured()` pour afficher un état d'erreur à l'utilisateur. Cependant, il est important de ne pas rendre le contenu original à l'origine de l'erreur, sinon le composant sera bloqué dans une boucle de rendu infinie.
Le hook peut retourner `false` pour empêcher la propagation de l'erreur. Consultez les détails sur la propagation des erreurs ci-dessous.
**Règles concernant la propagation des erreurs**
* Par défaut, toutes les erreurs sont envoyées à [`app.config.errorHandler`](/api/application#app-config-errorhandler) au niveau de l'application si elle est définie, afin qu'elles puissent être signalées et analysées par un seul service à un seul endroit.
* Si plusieurs hooks `errorCaptured` existent sur la chaîne descendante ou la chaîne ascendante d'un composant, ils seront tous invoqués sur la même erreur, suivant un ordre allant de bas en haut. Cela est comparable au mécanisme de *bubbling* des événements natifs du DOM.
* Si le hook `errorCaptured` lui-même lance une erreur, cette erreur et l'erreur capturée originellement sont envoyées à `app.config.errorHandler`.
* Un hook `errorCaptured` peut retourner `false` pour empêcher l'erreur de se propager plus loin. Cela revient à dire "cette erreur a été traitée et doit être ignorée". Cela empêchera tout autre hook `errorCaptured` ou `app.config.errorHandler` d'être invoqué pour cette erreur.
**Mises en garde concernant la capture d'erreurs**
* Dans les composants avec la fonction asynchrone `setup()` (avec le *top-level* `await`) Vue **essayera toujours** de rendre le template du composant, même si `setup()` a lancé une erreur. Cela causera probablement plus d'erreurs parce que pendant le rendu, le template du composant peut essayer d'accéder à des propriétés inexistantes du contexte `setup()` qui a échoué. Lorsque vous capturez des erreurs dans de tels composants, soyez prêt à gérer les erreurs provenant à la fois de l'échec de la fonction asynchrone `setup()` (elles arriveront toujours en premier) et de l'échec du processus de rendu.
* Remplacer le composant enfant erroné par le composant parent à l'intérieur de `` causera des erreurs d'hydratation dans SSR. Au lieu de cela, essayez de séparer la logique qui peut éventuellement être lancée depuis le `setup()` de l'enfant dans une fonction séparée et exécutez-la dans le `setup()` du composant parent, où vous pouvez en toute sécurité capturer avec `try/catch` le processus d'exécution et faire le remplacement si nécessaire avant de rendre le composant enfant actuel.
## renderTracked {#rendertracked}
Appelé lorsqu'une dépendance réactive a été traquée par l'effet de rendu du composant.
**Ce hook est réservé au mode développement et n'est pas appelé pendant le rendu côté serveur.**
* **Type :**
```ts
interface ComponentOptions {
renderTracked?(this: ComponentPublicInstance, e: DebuggerEvent): void
}
type DebuggerEvent = {
effect: ReactiveEffect
target: object
type: TrackOpTypes /* 'get' | 'has' | 'iterate' */
key: any
}
```
* **Voir aussi** [La réactivité en détails](/guide/extras/reactivity-in-depth)
## renderTriggered {#rendertriggered}
Appelé lorsqu'une dépendance réactive déclenche la ré-exécution de l'effet de rendu du composant.
**Ce hook est réservé au mode développement et n'est pas appelé pendant le rendu côté serveur.**
* **Type :**
```ts
interface ComponentOptions {
renderTriggered?(this: ComponentPublicInstance, e: DebuggerEvent): void
}
type DebuggerEvent = {
effect: ReactiveEffect
target: object
type: TriggerOpTypes /* 'set' | 'add' | 'delete' | 'clear' */
key: any
newValue?: any
oldValue?: any
oldTarget?: Map | Set
}
```
* **Voir aussi** [La réactivité en détails](/guide/extras/reactivity-in-depth)
## activated {#activated}
Appelé après l'insertion de l'instance du composant dans le DOM en tant que partie d'un arbre mis en cache par [``](/api/built-in-components#keepalive).
**Ce hook n'est pas appelé pendant le rendu côté serveur.**
* **Type :**
```ts
interface ComponentOptions {
activated?(this: ComponentPublicInstance): void
}
```
* **Voir aussi** [Guide - Cycle de vie d'une instance mise en cache](/guide/built-ins/keep-alive#lifecycle-of-cached-instance)
## deactivated {#deactivated}
Appelé après que l'instance du composant ait été retirée du DOM en tant que partie d'un arbre mis en cache par [``](/api/built-in-components#keepalive).
**Ce hook n'est pas appelé pendant le rendu côté serveur.**
* **Type :**
```ts
interface ComponentOptions {
deactivated?(this: ComponentPublicInstance): void
}
```
* **Voir aussi** [Guide - Cycle de vie d'une instance mise en cache](/guide/built-ins/keep-alive#lifecycle-of-cached-instance)
## serverPrefetch {#serverprefetch}
Fonction asynchrone qui doit être résolue avant que l'instance du composant ne soit rendue sur le serveur.
* **Type :**
```ts
interface ComponentOptions {
serverPrefetch?(this: ComponentPublicInstance): Promise
}
```
* **Détails**
Si le hook renvoie une promesse, le moteur de rendu du serveur attendra qu'elle soit résolue avant d'effectuer le rendu du composant.
Ce hook n'est appelé que pendant le rendu côté serveur et peut être utilisé pour effectuer une récupération de données sur le serveur uniquement.
* **Exemple**
```js
export default {
data() {
return {
data: null
}
},
async serverPrefetch() {
// le composant est rendu dans le cadre de la requête initiale.
// les données sont pré-récupérées sur le serveur car cela est plus rapide que via le client.
this.data = await fetchOnServer(/* ... */)
},
async mounted() {
if (!this.data) {
// si les données ne sont pas définies au moment du montage, cela signifie que le composant
// est rendu dynamiquement sur le client.
// Effectue la récupération côté client.
this.data = await fetchOnClient(/* ... */)
}
}
}
```
* **Voir aussi** [Rendu côté serveur](/guide/scaling-up/ssr)
---
---
url: /api/options-misc.md
---
# Options : Divers {#options-misc}
## name {#name}
Déclare explicitement un nom d'affichage pour le composant.
* **Type :**
```ts
interface ComponentOptions {
name?: string
}
```
* **Détails**
Le nom d'un composant est utilisé dans les cas suivants :
* L'auto-référence récursive dans le template du composant
* Affichage dans l'outil d'inspection de l'arbre des composants de Vue DevTools
* Affichage dans les avertissements concernant les composants
Lorsque vous utilisez des composants monofichiers, le composant déduit déjà son propre nom à partir du nom du fichier. Par exemple, un fichier nommé `MyComponent.vue` aura le nom d'affichage déduit "MyComponent".
Par ailleurs, lorsqu'un composant est enregistré de manière globale via [`app.component`](/api/application#app-component), l'ID global est automatiquement défini comme son nom.
L'option `name` vous permet de remplacer le nom déduit, ou de fournir explicitement un nom quand aucun nom ne peut être déduit (par exemple quand on n'utilise pas d'outil de build, ou lors de l'utilisation d'un composant en ligne divisé en plusieurs fichiers).
Il y a un cas où `name` est nécessaire : lors de la recherche d'un composant pouvant être mis en cache dans [``](/guide/built-ins/keep-alive) via ses props `include / exclude`.
:::tip
Depuis la version 3.2.34, un composant monofichier utilisant `
{{ label }}
```
Lorsque vous déclarez cette option dans un composant qui utilise `
{{ label }}
```
* **Voir aussi**
* [Attributs implicitement déclarés](/guide/components/attrs)
- [Utiliser `inheritAttrs` dans un `
```
```js{2}
export default {
inject: ['i18n'],
created() {
console.log(this.i18n.greetings.hello)
}
}
```
### Bundle pour NPM {#bundle-for-npm}
Si vous souhaitez ensuite créer et publier votre plugin pour que d'autres puissent l'utiliser, consultez [la section de Vite sur le mode bibliothèque](https://vite.dev/guide/build.html#library-mode).
---
---
url: /guide/essentials/component-basics.md
---
# Principes fondamentaux des composants {#components-basics}
Les composants nous permettent de fractionner l'UI en morceaux indépendants et réutilisables, sur lesquels nous pouvons réfléchir de manière isolée. Il est courant pour une application d'être organisée en un arbre de composants imbriqués.

Cette approche est très similaire à celle d'imbriquer des éléments HTML natifs, mais Vue implémente son propre modèle de composant, nous permettant d'encapsuler du contenu et de la logique au sein de chaque composant. Vue fonctionne également bien avec les Web Components natifs. Pour en savoir plus sur la relation entre les composants Vue et les Web Components natifs, [lisez ceci](/guide/extras/web-components).
## Définir un composant {#defining-a-component}
Lorsqu'on utilise des outils de build, on définit généralement chaque composant Vue dans un fichier dédié en utilisant l'extension `.vue` - aussi appelé [Composant monofichier](/guide/scaling-up/sfc) (ou Single-File Components en anglais, abrégé SFC) :
```vue
You clicked me {{ count }} times.
```
```vue
You clicked me {{ count }} times.
```
Sans outils de build, un composant Vue peut être défini comme un simple objet JavaScript contenant des options spécifiques à Vue :
```js
export default {
data() {
return {
count: 0
}
},
template: `
You clicked me {{ count }} times.
`
}
```
```js
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
},
template: `
You clicked me {{ count }} times.
`
// Peut également cibler un template dans le DOM :
// `template: '#my-template-element'`
}
```
Le template est écrit telle une chaîne de caractère JavaScript que Vue va compiler à la volée. Vous pouvez aussi utiliser un sélecteur d'ID pointant sur un élément (généralement des éléments natifs ``) - Vue utilisera son contenu comme la source du template.
L'exemple ci-dessus définit un composant et l'exporte comme l'export par défaut d'un fichier `.js`, mais vous pouvez utiliser les exports nommés pour exporter plusieurs composants à partir d'un même fichier.
## Utiliser un composant {#using-a-component}
:::tip
Nous allons utiliser la syntaxe SFC dans le reste de ce guide - les concepts des composants sont les mêmes que vous utilisiez des outils de build ou non. La section [Exemples](/examples/) illustre l'utilisation des composants dans les deux scénarios.
:::
Afin d'utiliser un composant enfant, nous devons l'importer dans le composant parent. En supposant que nous ayons placé notre composant compteur dans un fichier nommé `ButtonCounter.vue`, le composant apparaîtra comme l'export par défaut du fichier :
```vue
Here is a child component!
```
Pour exposer le composant importé à notre template, nous devons l'[enregistrer](/guide/components/registration) via l'option `components`. Le composant sera alors utilisable grâce à une balise portant la clé utilisée lors de l'enregistrement.
```vue
Here is a child component!
```
Avec `
{{ title }}
```
Lorsqu'une valeur est passée à un attribut prop, il devient une propriété de l'instance du composant. La valeur de cette propriété est accessible à l'intérieur du template et dans le contexte `this` du composant, tout comme n'importe quelle autre de ses propriétés.
```vue [BlogPost.vue]
{{ title }}
```
`defineProps` est une macro de compilation qui est seulement accessible à l'intérieur de `
```
```vue{4} [BlogPost.vue]
```
Cela documente tous les événements qu'un composant émet et peut éventuellement les [valider](/guide/components/events#events-validation). Cela permet également à Vue d'éviter de les appliquer implicitement en tant qu'écouteurs natifs à l'élément racine du composant enfant.
Comme c'est le cas pour `defineProps`, `defineEmits` n'est utilisable que dans `
```
Voir aussi : [Typer les emits d'un composant](/guide/typescript/composition-api#typing-component-emits)
Dans le cas où vous n'utilisez pas `
Has published books:
{{ publishedBooksMessage }}
```
[Essayer en ligne](https://play.vuejs.org/#eNp1kE9Lw0AQxb/KI5dtoTainkoaaREUoZ5EEONhm0ybYLO77J9CCfnuzta0vdjbzr6Zeb95XbIwZroPlMySzJW2MR6OfDB5oZrWaOvRwZIsfbOnCUrdmuCpQo+N1S0ET4pCFarUynnI4GttMT9PjLpCAUq2NIN41bXCkyYxiZ9rrX/cDF/xDYiPQLjDDRbVXqqSHZ5DUw2tg3zP8lK6pvxHe2DtvSasDs6TPTAT8F2ofhzh0hTygm5pc+I1Yb1rXE3VMsKsyDm5JcY/9Y5GY8xzHI+wnIpVw4nTI/10R2rra+S4xSPEJzkBvvNNs310ztK/RDlLLjy1Zic9cQVkJn+R7gIwxJGlMXiWnZEq77orhH3Pq2NH9DjvTfpfSBSbmA==)
Ici nous avons déclaré une propriété calculée `publishedBooksMessage`. La fonction `computed()` prend une [fonction accesseur](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description) en argument, et la valeur retournée est une **ref calculée**. De la même manière que pour les refs classiques, vous pouvez accéder au résultat calculé grâce à `publishedBooksMessage.value`. Les refs calculées sont automatiquement déballées dans les templates de manière à ce que vous puissiez y faire référence sans `.value` dans les expressions au sein du template.
Une propriété calculée traque automatiquement ses dépendances réactives. Vue sait que le calcul de `publishedBooksMessage` dépend de `author.books`, donc il va mettre à jour les liaisons dépendantes de `publishedBooksMessage` lorsque `author.books` change.
Voir aussi : [Typer les propriétés calculées](/guide/typescript/composition-api#typing-computed)
## Propriétés calculées mises en cache vs.. les méthodes {#computed-caching-vs-methods}
Vous avez peut-être remarqué que nous pouvons obtenir le même résultat en invoquant une méthode dans l'expression :
```vue-html
{{ calculateBooksMessage() }}
```
```js
// dans le composant
methods: {
calculateBooksMessage() {
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
```
```js
// dans le composant
function calculateBooksMessage() {
return author.books.length > 0 ? 'Yes' : 'No'
}
```
À la place d'une propriété calculée, nous pouvons définir la même fonction comme une méthode. Les deux approches mènent au même résultat final. Cependant, la différence est que **les propriétés calculées sont mises en cache en fonction de leurs dépendances réactives.** Une propriété calculée ne sera réévaluée que lorsque l'une de ses dépendances réactives aura changé. Cela signifie que tant que `author.books` n'a pas changé, les accès multiples à `publishedBooksMessage` vont immédiatement retourner le résultat calculé précédent sans avoir à réexécuter la fonction accesseur.
Cela signifie également que la propriété calculée suivante ne sera jamais mise à jour, car `Date.now()` n'est pas une dépendance réactive :
```js
computed: {
now() {
return Date.now()
}
}
```
```js
const now = computed(() => Date.now())
```
En comparaison, l'invocation d'une méthode va **toujours** exécuter la fonction, à chaque nouveau rendu.
Pourquoi avons nous besoin de la mise en cache ? Imaginons que nous ayons une propriété calculée conséquente `list`, qui nécessite de boucler à travers un important tableau et de réaliser de nombreuses opérations. Nous pourrions également avoir d'autres propriétés calculées dépendantes à leur tour de `list`. Sans mise en cache, nous exécuterions les accesseurs de `list` bien plus de fois que nécessaire ! Dans les cas où vous ne voulez pas de mise en cache, vous pouvez utiliser l'appel à une méthode.
## Propriétés calculées modifiables {#writable-computed}
Par défaut, les propriétés calculées ne sont soumises qu'aux accesseurs. Si vous essayez d'assigner une nouvelle valeur à une propriété calculée, vous aurez un avertissement au moment de l'exécution. Dans les rares cas où vous avez besoin d'une propriété calculée "modifiable", vous pouvez en créer une en lui fournissant à la fois un accesseur et un mutateur :
```js
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
computed: {
fullName: {
// accesseur
get() {
return this.firstName + ' ' + this.lastName
},
// mutateur
set(newValue) {
// Note : nous utilisons ici la syntaxe d'assignation par déstructuration.
;[this.firstName, this.lastName] = newValue.split(' ')
}
}
}
}
```
Désormais lorsque vous allez exécuter `this.fullName = 'John Doe'`, le mutateur sera invoqué et `this.firstName` et `this.lastName` seront mis à jour en conséquence.
```vue
```
Désormais lorsque vous allez exécuter `fullName.value = 'John Doe'`, le mutateur sera invoqué et `firstName` et `lastName` seront mis à jour en conséquence.
## Obtenir la valeur précédente {#previous}
* Supporté à partir de la version 3.4
```js
export default {
data() {
return {
count: 2
}
},
computed: {
// Ce calcul renvoie la valeur de count lorsqu'elle est inférieure ou égale à 3.
// Lorsque count est >=4, la dernière valeur qui remplit notre condition est renvoyée.
// jusqu'à ce que count soit inférieur ou égal à 3
alwaysSmall(_, previous) {
if (this.count <= 3) {
return this.count
}
return previous
}
}
}
```
```vue
```
Si vous utilisez un valeur calculée modifiable :
```js
export default {
data() {
return {
count: 2
}
},
computed: {
alwaysSmall: {
get(_, previous) {
if (this.count <= 3) {
return this.count
}
return previous;
},
set(newValue) {
this.count = newValue * 2
}
}
}
}
```
```vue
```
## Bonnes Pratiques {#best-practices}
### Les accesseurs ne doivent pas entraîner d'effets de bord {#getters-should-be-side-effect-free}
Il est important de se rappeler que les fonctions accesseurs de propriétés calculées doivent seulement réaliser des opérations pures et ne pas entraîner d'effets de bord. Par exemple, **ne faites pas de requêtes asynchrones ou ne mutez pas le DOM à l'intérieur d'un accesseur calculé !** Pensez à une propriété calculée comme une description déclarative de la manière d'obtenir une valeur selon d'autres valeurs - sa seule responsabilité devrait être de calculer et de retourner cette valeur. Plus loin dans le guide nous traiterons de la manière d'effectuer des effets de bord en réaction à des changements de l'état avec les [observateurs](./watchers).
### Évitez de modifier les valeurs calculées {#avoid-mutating-computed-value}
La valeur retournée par une propriété calculée est un état dérivé. Pensez-y comme un snapshot temporaire - chaque fois que l'état de base change, un nouveau snapshot est créé. Il n'est pas logique de modifier un snapshot, donc une valeur calculée retournée ne devrait être traitée qu'en lecture seule et ne pas être modifiée - à la place, modifiez l'état de base dont elle dépend afin d'engendrer de nouveaux calculs.
---
---
url: /guide/components/props.md
---
# Props {#props}
> Cette page suppose que vous avez déjà lu les [principes fondamentaux des composants](/guide/essentials/component-basics). Lisez-les d'abord si vous débutez avec les composants.
## Déclaration de props {#props-declaration}
Les composants Vue nécessitent une déclaration explicite des props afin que Vue sache quels props externes passés au composant doivent être traités comme des attributs implicitement déclarés (qui seront discutés dans [sa section dédiée](/guide/components/attrs)).
Dans les SFC utilisant `
```
Dans les composants autres que `
```
Plus de détails: [Typage de props de composant](/guide/typescript/composition-api#typing-component-props)
## Déstructuration réactive des props \*\* {#reactive-props-destructure}
Le système de réactivité de Vue suit l'utilisation de l'état en fonction de l'accès à la propriété. Par exemple, lorsque vous accédez à `props.foo` dans une computed ou un watcher, la prop `foo` est suivie comme une dépendance.
Ainsi, selon le code suivant :
```js
const { foo } = defineProps(['foo'])
watchEffect(() => {
// ne s'exécute qu'une seule fois avant 3.5
// se ré-exécute lorsque la prop "foo" est modifiée dans la version 3.5+.
console.log(foo)
})
```
Dans les versions 3.4 et inférieures, `foo` est une constante réelle et ne changera jamais. Dans les versions 3.5 et supérieures, le compilateur de Vue ajoute automatiquement le préfixe `props.` lorsque le code dans le même bloc `
```
Si vous n'utilisez pas `
```
Si plusieurs parents fournissent des données avec la même clé, l'injection se résoudra à la valeur du parent le plus proche dans la chaîne des parents du composant.
Si la valeur fournie est une référence, elle sera injectée telle quelle et **ne sera pas** automatiquement exposée. Cela permet au composant injecteur de conserver la connexion de réactivité au composant fournisseur.
[Exemple complet provide + inject avec réactivité](https://play.vuejs.org/#eNqFUUFugzAQ/MrKF1IpxfeIVKp66Kk/8MWFDXYFtmUbpArx967BhURRU9/WOzO7MzuxV+fKcUB2YlWovXYRAsbBvQije2d9hAk8Xo7gvB11gzDDxdseCuIUG+ZN6a7JjZIvVRIlgDCcw+d3pmvTglz1okJ499I0C3qB1dJQT9YRooVaSdNiACWdQ5OICj2WwtTWhAg9hiBbhHNSOxQKu84WT8LkNQ9FBhTHXyg1K75aJHNUROxdJyNSBVBp44YI43NvG+zOgmWWYGt7dcipqPhGZEe2ef07wN3lltD+lWN6tNkV/37+rdKjK2rzhRTt7f3u41xhe37/xJZGAL2PLECXa9NKdD/a6QTTtGnP88LgiXJtYv4BaLHhvg==)
Encore une fois, si vous n'utilisez pas `
```
```vue{5}
{{ location }}
```
Enfin, vous pouvez encapsuler la valeur fournie avec [`readonly()`](/api/reactivity-core#readonly) si vous souhaitez vous assurer que les données transmises via `provide` ne puissent pas être mutées par le composant réalisant l'injection.
```vue
```
Afin de rendre les injections liées de manière réactive au fournisseur, nous devons fournir une propriété calculée à l'aide de la fonction [computed()](/api/reactivity-core#computed) :
```js{12}
import { computed } from 'vue'
export default {
data() {
return {
message: 'hello!'
}
},
provide() {
return {
// fournir explicitement une propriété calculée
message: computed(() => this.message)
}
}
}
```
[Exemple complet provide + inject avec réactivité](https://play.vuejs.org/#eNqNUctqwzAQ/JVFFyeQxnfjBEoPPfULqh6EtYlV9EKWTcH43ytZtmPTQA0CsdqZ2dlRT16tPXctkoKUTeWE9VeqhbLGeXirheRwc0ZBds7HKkKzBdBDZZRtPXIYJlzqU40/I4LjjbUyIKmGEWw0at8UgZrUh1PscObZ4ZhQAA596/RcAShsGnbHArIapTRBP74O8Up060wnOO5QmP0eAvZyBV+L5jw1j2tZqsMp8yWRUHhUVjKPoQIohQ460L0ow1FeKJlEKEnttFweijJfiORElhCf5f3umObb0B9PU/I7kk17PJj7FloN/2t7a2Pj/Zkdob+x8gV8ZlMs2de/8+14AXwkBngD9zgVqjg2rNXPvwjD+EdlHilrn8MvtvD1+Q==)
La fonction `computed()` est généralement utilisée dans les composants utilisant la Composition API, mais peut également être utilisée pour compléter certains cas d'usage avec l'Options API. Vous pouvez en savoir plus sur son utilisation en lisant [les fondamentaux de la réactivité](/guide/essentials/reactivity-fundamentals) et [les propriétés calculées](/guide/essentials/computed) avec la préférence d'API définie sur Composition API.
## Injection avec des Symbols en tant que clés {#working-with-symbol-keys}
Jusqu'à présent, nous avons utilisé dans les exemples des clés d'injection qui étaient des chaînes de caractères. Si vous travaillez dans une application de taille importante avec de nombreux fournisseurs de dépendances, ou si vous créez des composants qui seront utilisés par d'autres développeurs, il est préférable d'utiliser des clés d'injection utilisant des [Symbols](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Symbol) pour éviter les collisions potentielles.
Il est recommandé d'exporter les Symbols dans un fichier dédié :
```js [keys.js]
export const myInjectionKey = Symbol()
```
```js
// dans le composant fournisseur
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, {
/* données à fournir */
})
```
```js
// dans le composant injecteur
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)
```
Voir aussi : [Définir le type des données avec Provide / Inject](/guide/typescript/composition-api#typing-provide-inject)
```js
// dans le composant fournisseur
import { myInjectionKey } from './keys.js'
export default {
provide() {
return {
[myInjectionKey]: {
/* données à fournir */
}
}
}
}
```
```js
// dans le composant injecteur
import { myInjectionKey } from './keys.js'
export default {
inject: {
injected: { from: myInjectionKey }
}
}
```
---
---
url: /guide/extras/reactivity-transform.md
---
# Reactivity Transform {#reactivity-transform}
:::danger Fonctionnalité expérimentale dépréciée
Reactivity Transform était une fonctionnalité expérimentale, et a été supprimée dans la dernière version 3.4. Consultez [le raisonnement ici](https://github.com/vuejs/rfcs/discussions/369#discussioncomment-5059028).
Si vous voulez continuer de l'utiliser, cela est désormais possible en utilisant le plugin [Vue Macros](https://vue-macros.sxzz.moe/features/reactivity-transform.html).
:::
:::tip Spécifique à la Composition API
Reactivity Transform est une fonctionnalité spécifique à la Composition API et nécessite un outil de build.
:::
## Refs vs. variables réactives {#refs-vs-reactive-variables}
Depuis l'introduction de la Composition API, l'une des principales questions non résolues est l'utilisation des refs par rapport aux objets réactifs. Il est facile de perdre la réactivité lors de la déstructuration des objets réactifs, mais il peut être fastidieux d'utiliser `.value` partout lors de l'utilisation des refs. De plus, `.value` est facilement oubliable si l'on n'utilise pas un système de typage.
[Reactivity Transform de Vue](https://github.com/vuejs/core/tree/main/packages/reactivity-transform) consiste en une transformation réalisée au moment de la compilation, nous permettant d'écrire du code comme celui-ci :
```vue
{{ count }}
```
La méthode `$ref()` est ici une **macro de compilation** : ce n'est pas une méthode réelle qui sera appelée à l'exécution. Au lieu de cela, le compilateur Vue l'utilise comme une indication pour traiter la variable `count` qui en résulte comme une **variable réactive**.
Les variables réactives peuvent être accédées et réassignées comme des variables normales, mais ces opérations sont compilées en des refs avec `.value`. Par exemple, la partie `
```
Ce qui précède sera compilé en un équivalent de la déclaration d'exécution suivante :
```js
export default {
props: {
msg: { type: String, required: true },
count: { type: Number, default: 1 },
foo: String
},
setup(props) {
watchEffect(() => {
console.log(props.msg, props.count, props.foo)
})
}
}
```
## Conserver la réactivité au-delà des frontières des fonctions {#retaining-reactivity-across-function-boundaries}
Bien que les variables réactives nous évitent de devoir utiliser `.value` partout, cela crée un problème de "perte de réactivité" lorsque nous passons des variables réactives à travers les frontières des fonctions. Cela peut se produire dans deux cas :
### Passage dans une fonction comme argument {#passing-into-function-as-argument}
Prenons une fonction qui attend une ref comme argument, par exemple :
```ts
function trackChange(x: Ref) {
watch(x, (x) => {
console.log('x changed!')
})
}
let count = $ref(0)
trackChange(count) // ne fonctionne pas !
```
Le cas ci-dessus ne fonctionnera pas comme prévu car il sera compilé en :
```ts
let count = ref(0)
trackChange(count.value)
```
Ici, `count.value` est passée comme un nombre, alors que `trackChange` attend une ref réelle. Cela peut être corrigé en enveloppant `count` avec `$$()` avant de le passer :
```diff
let count = $ref(0)
- trackChange(count)
+ trackChange($$(count))
```
Se compile comme suit :
```js
import { ref } from 'vue'
let count = ref(0)
trackChange(count)
```
Comme nous pouvons le voir, `$$()` est une macro qui sert d'indice **échappatoire** : les variables réactives contenues dans `$$()` ne se verront pas ajouter `.value`.
### Retour à l'intérieur du scope d'une fonction {#returning-inside-function-scope}
La réactivité peut également être perdue si les variables réactives sont utilisées directement dans une expression retournée :
```ts
function useMouse() {
let x = $ref(0)
let y = $ref(0)
// écout les mouvements de la souris...
// ne fonctionne pas !
return {
x,
y
}
}
```
L'instruction de retour ci-dessus se compile comme suit :
```ts
return {
x: x.value,
y: y.value
}
```
Afin de conserver la réactivité, nous devrions renvoyer les refs réelles, et non la valeur actuelle au moment du retour.
Encore une fois, nous pouvons utiliser `$$()` pour résoudre ce problème. Dans ce cas, `$$()` peut être utilisée directement sur l'objet retourné - toute référence à des variables réactives à l'intérieur de l'appel `$$()` conservera la référence à leurs refs sous-jacentes :
```ts
function useMouse() {
let x = $ref(0)
let y = $ref(0)
// écoute les mouvements de la souris...
// corrigé
return $$({
x,
y
})
}
```
### Utiliser `$$()` sur des props déstructurées {#using-on-destructured-props}
`$$()` fonctionne sur les props déstructurées puisqu'elles sont elles aussi des variables réactives. Le compilateur le convertira avec `toRef` pour plus d'efficacité :
```ts
const { count } = defineProps<{ count: number }>()
passAsRef($$(count))
```
Se compile comme suit :
```js
setup(props) {
const __props_count = toRef(props, 'count')
passAsRef(__props_count)
}
```
## Intégration avec TypeScript {#typescript-integration}
Vue fournit des typages pour ces macros (disponibles globalement) et tous les types fonctionneront comme prévu. Il n'y a aucune incompatibilité avec la sémantique TypeScript standard, et donc la syntaxe fonctionnera avec tous les outils existants.
Cela signifie également que les macros peuvent fonctionner dans n'importe quel fichier où les JS / TS valides sont autorisés - pas seulement dans les SFC de Vue.
Puisque les macros sont disponibles globalement, leurs types doivent être explicitement référencés (par exemple dans un fichier `env.d.ts`) :
```ts
///
```
Si vous importez explicitement les macros à partir de `vue/macros`, le type fonctionnera sans déclarer les globaux.
## Activation explicite {#explicit-opt-in}
:::warning
Ce qui suit ne s'applique qu'aux versions 3.3 et inférieures de Vue. La prise en charge par le noyau a été supprimée depuis la version 3.4, et la version 5 et plus de `@vitejs/plugin-vue`. Si vous voulez continuer à utiliser la transformation, veuillez migrer vers [Vue Macros](https://vue-macros.sxzz.moe/features/reactivity-transform.html) à la place.
:::
### Vite {#vite}
* Nécessite `@vitejs/plugin-vue@>=2.0.0`.
* S'applique aux SFC et aux fichiers js(x)/ts(x). Une vérification rapide de l'utilisation est effectuée sur les fichiers avant d'appliquer la transformation, il ne devrait donc pas y avoir de perte de performance pour les fichiers n'utilisant pas les macros.
* Notez que `reactivityTransform` est désormais une option au niveau de la racine du plugin au lieu d'être imbriquée comme `script.refSugar`, puisqu'elle n'affecte pas seulement les SFC.
```js [vite.config.js]
export default {
plugins: [
vue({
reactivityTransform: true
})
]
}
```
### `vue-cli` {#vue-cli}
* N'affecte actuellement que les SFC
* Nécessite `vue-loader@>=17.0.0`.
```js [vue.config.js]
module.exports = {
chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
.tap((options) => {
return {
...options,
reactivityTransform: true
}
})
}
}
```
### `webpack` simple + `vue-loader` {#plain-webpack-vue-loader}
* N'affecte actuellement que les SFC
* Nécessite `vue-loader@>=17.0.0`.
```js [webpack.config.js]
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
reactivityTransform: true
}
}
]
}
}
```
---
---
url: /error-reference.md
---
# Référence des codes d'erreur en production {#error-reference}
## Erreurs d'exécution {#runtime-errors}
Dans les versions de production, le troisième argument transmis aux API de gestion des erreurs suivantes sera un code court au lieu de la chaîne d'information complète :
* [`app.config.errorHandler`](/api/application#app-config-errorhandler)
* [`onErrorCaptured`](/api/composition-api-lifecycle#onerrorcaptured) (Composition API)
* [`errorCaptured`](/api/options-lifecycle#errorcaptured) (Options API)
Le tableau suivant établit une correspondance entre les codes et leurs chaînes d'information complètes d'origine.
## Erreurs de compilation {#compiler-errors}
Le tableau suivant fournit une correspondance entre les codes d'erreur du compilateur en production et leurs messages d'origine.
---
---
url: /style-guide/rules-essential.md
---
# Règles de priorité A : Essentielles {#priority-a-rules-essential}
Ces règles aident à prévenir les erreurs, donc apprenez les et tenez-y vous coûte que coûte. Il peut y avoir des exceptions, mais elles sont rares et devraient être faites par ceux ayant une expertise à la fois dans JavaScript et dans Vue.
## Utilisez des noms de composants avec plusieurs mots {#use-multi-word-component-names}
Les noms de composants créés par l'utilisateur devraient toujours être composés de plusieurs mots, à l'exception du composant racine `App`. Cela [évite les conflits](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) avec les éléments HTML existants et à venir, puisqu'ils sont tous composés d'un seul mot.
```vue-html
```
```vue-html
```
## Utilisez des définitions de prop détaillées {#use-detailed-prop-definitions}
Dans le code source, les définitions de prop devraient toujours être le plus détaillées possible, en spécifiant au moins le ou les types.
::: details Explications détaillées
[Les définitions de prop](/guide/components/props#prop-validation) détaillées présentent deux avantages :
* Elles documentent l'API du composant, de manière à ce qu'il soit facile de voir comment le composant doit être utilisé.
* Pendant le développement, Vue vous avertira si jamais un composant se voit fournir des props au mauvais format, ce qui vous aidera à régler les potentielles sources d'erreurs.
:::
```js
// OK seulement lorsque vous prototyper
props: ['status']
```
```js
props: {
status: String
}
```
```js
// Encore mieux !
props: {
status: {
type: String,
required: true,
validator: value => {
return [
'syncing',
'synced',
'version-conflict',
'error'
].includes(value)
}
}
}
```
```js
// OK seulement lorsque vous prototyper
const props = defineProps(['status'])
```
```js
const props = defineProps({
status: String
})
```
```js
// Encore mieux !
const props = defineProps({
status: {
type: String,
required: true,
validator: (value) => {
return ['syncing', 'synced', 'version-conflict', 'error'].includes(
value
)
}
}
})
```
## Utilisez `v-for` avec une clé {#use-keyed-v-for}
`key` avec `v-for` est *toujours* requis sur les composants, afin de maintenir l'état interne du composant à travers le sous-arbre. Cependant même pour les éléments, une bonne pratique est de maintenir un comportement prédictible, telle que [la persistance de l'objet](https://bost.ocks.org/mike/constancy/) dans les animations.
::: details Explications détaillées
Imaginons que vous ayez une liste de todos :
```js
data() {
return {
todos: [
{
id: 1,
text: 'Learn to use v-for'
},
{
id: 2,
text: 'Learn to use key'
}
]
}
}
```
```js
const todos = ref([
{
id: 1,
text: 'Learn to use v-for'
},
{
id: 2,
text: 'Learn to use key'
}
])
```
Puis vous les triez par ordre alphabétique. Lors de la mise à jour du DOM, Vue va optimiser le rendu de manière à réaliser les mutations du DOM les moins coûteuses. Cela peut signifier supprimer la première todo, puis la remettre à la fin de la liste.
Le problème est que, dans certains cas il peut être important de ne pas supprimer d'éléments qui vont rester dans le DOM. Par exemple, vous pouvez vouloir utiliser `` pour animer le tri de la liste, ou maintenir le focus si l'élément rendu est un ` `. Dans ces cas, ajouter une clé unique pour chaque item (par exemple `:key="todo.id"`) précisera de manière plus prédictible à Vue comment se comporter.
De notre expérience, il est préférable de *toujours* ajouter une clé unique, de sorte que vous et votre équipe n'ayez jamais à vous soucier de ces rares cas. Dans les scenarios rares et critiques, d'un point de vue des performances, où la persistance de l'objet n'est pas nécessaire, vous pouvez faire une exception.
:::
```vue-html
```
```vue-html
```
## Évitez les `v-if` avec les `v-for` {#avoid-v-if-with-v-for}
**N'utilisez jamais `v-if` et `v-for` sur le même élément.**
Il y a deux situations courantes où cela peut être tentant :
* Pour filtrer des items dans une liste (par exemple `v-for="user in users" v-if="user.isActive"`). Dans ces cas, remplacez `users` par une nouvelle propriété calculée qui vous retourne votre liste filtrée (par exemple `activeUsers`).
* Pour éviter le rendu d'une liste si elle doit être cachée (par exemple `v-for="user in users" v-if="shouldShowUsers"`). Dans ces cas, déplacez le `v-if` sur un élément conteneur (par exemple `ul`, `ol`).
::: details Explications détaillées
Lorsque Vue traite les directives, `v-if` a la priorité sur `v-for`, donc ce template :
```vue-html
```
Va produire une erreur, car la directive `v-if` sera d'abord évaluée et la variable d'itération `user` n'existe pas à ce moment précis.
Cela peut être résolu en itérant sur une propriété calculée à la place, de cette façon :
```js
computed: {
activeUsers() {
return this.users.filter(user => user.isActive)
}
}
```
```js
const activeUsers = computed(() => {
return users.filter((user) => user.isActive)
})
```
```vue-html
```
Ou encore, nous pouvons utiliser une balise `` avec `v-for` pour envelopper l'élément `` :
```vue-html
```
:::
```vue-html
```
```vue-html
```
```vue-html
```
## Utilisez du style avec une portée limitée au composant {#use-component-scoped-styling}
Pour les applications, les styles du composant `App` et des composants de mise en page peuvent être globaux, mais tous les autres styles des composants devraient avoir une portée limitée.
Cela n'est pertinent que pour les [composants monofichiers](/guide/scaling-up/sfc). Cela ne nécessite *pas* que l'[attribut `scoped`](/api/sfc-css-features#scoped-css) soit utilisé. La limitation de la portée peut se faire via des [modules CSS](/api/sfc-css-features#css-modules), une stratégie basée sur les classes telle que [BEM](https://getbem.com/), ou tout autre librairie/convention.
**Toutefois, pour les librairies de composants, il est préférable d'utiliser une stratégie basée sur les classes au lieu d'utiliser l'attribut `scoped`.**
Cela permet de remplacer les styles internes plus facilement, avec des noms de classe compréhensibles par des humains et qui ne sont pas trop spécifiques, mais ont tout de même qu'une faible probabilité d'être à l'origine d'un conflit.
::: details Explications détaillées
Si vous développez un projet conséquent, travaillez avec d'autres développeurs, or incluez parfois du HTML/CSS tiers (par exemple à partir d'Auth0), une gestion des portées cohérente assurera que vos styles ne s'appliquent qu'aux composants pour lesquels ils sont destinés.
Au-delà de l'attribut `scoped`, utiliser des noms de classe uniques permet de s'assurer que du CSS tiers ne s'applique pas à votre HTML. Par exemple, de nombreux projets utilise les noms de classe `button`, `btn`, ou `icon`, donc même si vous n'utilisez pas de stratégie comme BEM, ajouter un préfixe spécifique à votre application ou votre composant (par exemple `ButtonClose-icon`) peut fournir une certaine protection.
:::
```vue-html
×
```
```vue-html
×
```
```vue-html
×
```
```vue-html
×
```
---
---
url: /style-guide/rules-strongly-recommended.md
---
# Règles de priorité B : Fortement recommandées {#priority-b-rules-strongly-recommended}
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 {#component-files}
**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.
```js
app.component('TodoList', {
// ...
})
app.component('TodoItem', {
// ...
})
```
```
components/
|- TodoList.js
|- TodoItem.js
```
```
components/
|- TodoList.vue
|- TodoItem.vue
```
## La casse des noms de composants {#single-file-component-filename-casing}
**Le nom des [composants monofichiers](/guide/scaling-up/sfc) 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.
```
components/
|- mycomponent.vue
```
```
components/
|- myComponent.vue
```
```
components/
|- MyComponent.vue
```
```
components/
|- my-component.vue
```
## Nom des composants de base {#base-component-names}
**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`.**
::: details 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 Vite :
```js
const modules = import.meta.glob('./src/**/Base*.vue', { eager: true })
for (const path in modules) {
const config = modules[path].default
const name = config.name || path.match(/Base[A-Z]\w+/)[0]
app.component(name, config)
}
```
:::
```
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
```
## Noms des composants étroitement liés {#tightly-coupled-component-names}
**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.
::: details 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.
:::
```
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
```
```
components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue
```
```
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
```
```
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue
```
## Ordre des mots dans les noms des composants {#order-of-words-in-component-names}
**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.**
::: details 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é.
:::
```
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
```
## Composants auto-fermants {#self-closing-components}
**Les composants sans contenu doivent être auto-fermants dans les [composants monofichiers](/guide/scaling-up/sfc), dans les templates, et dans [JSX](/guide/extras/render-function#jsx-tsx) - 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"](https://html.spec.whatwg.org/multipage/syntax.html#void-elements). 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.
```vue-html
```
```vue-html
```
```vue-html
```
```vue-html
```
## La casse des noms de composants dans les templates {#component-name-casing-in-templates}
**Dans la plupart des projets, les noms de composants doivent toujours être en PascalCase dans les [composants monofichiers](/guide/scaling-up/sfc) 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.
* `` est visuellement plus distinct d'un élément HTML que ``, 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**.
```vue-html
```
```vue-html
```
```vue-html
```
```vue-html
```
```vue-html
```
OU
```vue-html
```
## La casse des noms de composants en JS/JSX {#component-name-casing-in-js-jsx}
**Les noms de composants en JS/[JSX](/guide/extras/render-function#jsx-tsx) 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`.**
::: details 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](#component-name-casing-in-templates).
:::
```js
app.component('myComponent', {
// ...
})
```
```js
import myComponent from './MyComponent.vue'
```
```js
export default {
name: 'myComponent'
// ...
}
```
```js
export default {
name: 'my-component'
// ...
}
```
```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 {#full-word-component-names}
**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.
```
components/
|- SdSettings.vue
|- UProfOpts.vue
```
```
components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
```
## La casse des noms de prop {#prop-name-casing}
**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](/guide/extras/render-function#jsx-tsx) 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.**
```js
props: {
'greeting-text': String
}
```
```js
const props = defineProps({
'greeting-text': String
})
```
```vue-html
// for in-DOM templates
```
```js
props: {
greetingText: String
}
```
```js
const props = defineProps({
greetingText: String
})
```
```vue-html
// 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
// ou
```
```vue-html
// pour les template du DOM
```
## Éléments à attributs multiples {#multi-attribute-elements}
**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](/guide/extras/render-function#jsx-tsx) méritent la même considération.
```vue-html
```
```vue-html
```
```vue-html
```
```vue-html
```
## Expressions simples dans les templates {#simple-expressions-in-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.
```vue-html
{{
fullName.split(' ').map((word) => {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
```
```vue-html
{{ normalizedFullName }}
```
```js
// L'expression complexe a été déplacée vers une propriété calculée
computed: {
normalizedFullName() {
return this.fullName.split(' ')
.map(word => word[0].toUpperCase() + word.slice(1))
.join(' ')
}
}
```
```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 {#simple-computed-properties}
**Les propriétés calculées complexes doivent être divisées en propriétés plus simples.**
::: details 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.
:::
```js
computed: {
price() {
const basePrice = this.manufactureCost / (1 - this.profitMargin)
return (
basePrice -
basePrice * (this.discountPercent || 0)
)
}
}
```
```js
const price = computed(() => {
const basePrice = manufactureCost.value / (1 - profitMargin.value)
return basePrice - basePrice * (discountPercent.value || 0)
})
```
```js
computed: {
basePrice() {
return this.manufactureCost / (1 - this.profitMargin)
},
discount() {
return this.basePrice * (this.discountPercent || 0)
},
finalPrice() {
return this.basePrice - this.discount
}
}
```
```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 {#quoted-attribute-values}
**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.
```vue-html
```
```vue-html
```
```vue-html
```
```vue-html
```
## Les raccourcis de directives {#directive-shorthands}
**Les raccourcis de directives (`:` pour `v-bind:`, `@` pour `v-on:` et `#` pour `v-slot`) doivent toujours être utilisés ou ne jamais l'être.**
```vue-html
```
```vue-html
```
```vue-html
Ceci est le titre de la page
Ici quelques infos contacts
```
```vue-html
```
```vue-html
```
```vue-html
```
```vue-html
```
```vue-html
Here might be a page title
Here's some contact info
```
```vue-html
Here might be a page title
Here's some contact info
```
---
---
url: /style-guide/rules-recommended.md
---
# Règles de priorité C : Recommandées {#priority-c-rules-recommended}
Lorsqu'il existe plusieurs options correctes, un choix arbitraire peut être fait pour assurer une certaine cohérence. Dans ces règles, nous décrivons chaque option acceptable et suggérons un choix par défaut. Cela signifie que vous être libres de faire un choix différent dans votre code, tant que vous restez cohérent et avez une bonne raison. Vous avez certainement une bonne raison ! En adaptant les standards de la communauté, vous :
1. Entraînerez votre cerveau à analyser plus facilement la plupart du code que vous rencontrerez
2. Serez capable de copier et coller la plupart du code de la communauté sans modification
3. Réaliserez souvent que les nouvelles recrues sont habituées à votre style de code favori, du moins en ce qui concerne Vue
## Ordre des options du composant/de l'instance {#component-instance-options-order}
**Les options du composant/de l'instance devraient être ordonnées de manière constante.**
Voici l'ordre par défaut que nous recommandons pour les options d'un composant. Les options sont divisées en catégories, afin que vous sachiez où ajouter de nouvelles propriétés depuis les plugins.
1. **Conscience globale** (requiert des informations au-delà du composant)
* `name`
2. **Options du compilateur de templates** (change la manière dont les templates sont compilés)
* `compilerOptions`
3. **Dépendances du template** (ressources utilisées dans le template)
* `components`
* `directives`
4. **Composition** (fusionne les propriétés dans les options)
* `extends`
* `mixins`
* `provide`/`inject`
5. **Interface** (l'interface du composant)
* `inheritAttrs`
* `props`
* `emits`
* `expose`
6. **Composition API** (le point d'entrée pour l'utilisation de la Composition API)
* `setup`
7. **État local** (propriétés réactives locales)
* `data`
* `computed`
8. **Événements** (fonctions de rappel déclenchées par des événements réactifs)
* `watch`
* Événements du cycles de vie (dans l'ordre où ils sont appelés)
* `beforeCreate`
* `created`
* `beforeMount`
* `mounted`
* `beforeUpdate`
* `updated`
* `activated`
* `deactivated`
* `beforeUnmount`
* `unmounted`
* `errorCaptured`
* `renderTracked`
* `renderTriggered`
* `serverPrefetch` (SSR seulement)
9. **Propriétés non réactives** (propriétés de l'instance indépendantes du système de réactivité)
* `methods`
10. **Rendu** (la description déclaratif du résultat du composant)
* `template`/`render`
## Ordre des attributs des éléments {#element-attribute-order}
**Les attributs des éléments (et des composants) devraient être ordonnés de manière constante.**
Voici l'ordre par défaut que nous recommandons pour les options d'un composant. Les options sont divisées en catégories, afin que vous sachiez où ajouter des attributs personnalisés et des directives.
1. **Définition** (fourni les options du composant)
* `is`
2. **Rendu de liste** (crée plusieurs variations d'un même élément)
* `v-for`
3. **Conditionnelles** (indiquent si l'élément est rendu/affiché)
* `v-if`
* `v-else-if`
* `v-else`
* `v-show`
* `v-cloak`
4. **Modificateurs du rendu** (changent la façon dont l'élément est rendu)
* `v-pre`
* `v-once`
5. **Conscience globale** (requiert des informations au-delà du composant)
* `id`
6. **Attributs uniques** (attributs nécessitant des valeurs uniques)
* `ref`
* `key`
7. **Liaison bidirectionnelle** (combinaison de la liaison et des événements)
* `v-model`
8. **Autres attributs** (tous les attributs liés et non liés non spécifiés)
9. **Événements** (écouteurs d'événements du composant)
* `v-on`
10. **Contenu** (remplace le contenu de l'élément)
* `v-html`
* `v-text`
## Lignes vides dans les options du composant/de l'instance {#empty-lines-in-component-instance-options}
**Vous pouvez être tenté d'ajouter une ligne vide entre les propriétés multi-lignes, notamment si les options ne peuvent plus tenir sur votre écran sans défilement.**
Lorsque les composants commencent à prendre beaucoup d'espace ou deviennent difficiles à lire, l'ajout d'espaces entre les propriétés multi-lignes peut les rendre plus faciles à parcourir. Dans certains éditeurs, comme Vim, des options de formatage comme celle-ci peuvent également faciliter la navigation au clavier.
```js
props: {
value: {
type: String,
required: true
},
focused: {
type: Boolean,
default: false
},
label: String,
icon: String
},
computed: {
formattedValue() {
// ...
},
inputClasses() {
// ...
}
}
```
```js
// Sans espace c'est aussi bon tant que
// le composant soit toujours facile à lire
props: {
value: {
type: String,
required: true
},
focused: {
type: Boolean,
default: false
},
label: String,
icon: String
},
computed: {
formattedValue() {
// ...
},
inputClasses() {
// ...
}
}
```
```js
defineProps({
value: {
type: String,
required: true
},
focused: {
type: Boolean,
default: false
},
label: String,
icon: String
})
const formattedValue = computed(() => {
// ...
})
const inputClasses = computed(() => {
// ...
})
```
```js
defineProps({
value: {
type: String,
required: true
},
focused: {
type: Boolean,
default: false
},
label: String,
icon: String
})
const formattedValue = computed(() => {
// ...
})
const inputClasses = computed(() => {
// ...
})
```
## Ordre des éléments de premier niveau des composants monofichiers {#single-file-component-top-level-element-order}
**[Les composants monofichiers](/guide/scaling-up/sfc) devraient toujours ordonner les balises `
...
```
```vue-html [ComponentA.vue]
...
```
```vue-html [ComponentB.vue]
...
```
```vue-html [ComponentA.vue]
...
```
```vue-html [ComponentB.vue]
...
```
```vue-html [ComponentA.vue]
...
```
```vue-html [ComponentB.vue]
...
```
---
---
url: /style-guide/rules-use-with-caution.md
---
# Règles de priorité D: À utiliser avec précaution {#priority-d-rules-use-with-caution}
Certaines fonctionnalités de Vue existent pour prévoir de rares cas particuliers ou des migrations plus douces depuis une base de code héritée. Toutefois, lorsqu'elles sont surexploitées, elles peuvent rendre le code plus difficile à maintenir ou même devenir une source de bugs. Ces règles mettent en lumière ces fonctionnalités potentiellement risquées, en décrivant quand et pourquoi elles devraient être évitées.
## Sélecteurs d'éléments avec `scoped` {#element-selectors-with-scoped}
**Les sélecteurs d'éléments ne devraient pas être utilisés avec `scoped`.**
Préférez les sélecteurs de classes aux sélecteurs d'éléments dans les styles `scoped`, parce qu'un grand nombre de sélecteurs d'éléments sont lents.
::: details Explications détaillées
Pour limiter la portée des styles, Vue ajoute un attribut unique aux éléments des composants, tel que `data-v-f3f3eg9`. Les sélecteurs sont ensuite modifiés de manière à ce que seuls les éléments correspondant à cet attribut soient sélectionnés (par exemple `button[data-v-f3f3eg9]`).
Le problème est qu'un large nombre de sélecteurs d'éléments-attributs (par exemple `button[data-v-f3f3eg9]`) sera considérablement plus lent que des sélecteurs de classes-attributs (par exemple `.btn-close[data-v-f3f3eg9]`), donc les sélecteurs de classes doivent être privilégiés lorsque c'est possible.
:::
```vue-html
×
```
```vue-html
×
```
## Communication parent-enfant implicite {#implicit-parent-child-communication}
**Les props et les événements doivent être privilégiés pour la communication entre les composants parent-enfant, plutôt que `this.$parent` ou les props mutants.**
Une application Vue idéale est composée de flux de props vers le bas, et d'événements vers le haut. Respecter cette convention rendra vos composants beaucoup plus faciles à comprendre. Cependant, il existe des cas limites où la mutation de prop ou `this.$parent` peuvent simplifier deux composants déjà profondément couplés.
Le problème, c'est qu'il existe aussi de nombreux cas *simples* où ces modèles peuvent être pratiques. Attention : ne vous laissez pas séduire par l'idée d'échanger la simplicité (être capable de comprendre le flux de votre état) contre la commodité à court terme (écrire moins de code).
```js
app.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
template: ' '
})
```
```js
app.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
methods: {
removeTodo() {
this.$parent.todos = this.$parent.todos.filter(
(todo) => todo.id !== vm.todo.id
)
}
},
template: `
{{ todo.text }}
×
`
})
```
```js
app.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
emits: ['input'],
template: `
`
})
```
```js
app.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
emits: ['delete'],
template: `
{{ todo.text }}
×
`
})
```
```vue
```
```vue
{{ todo.text }}
renommer
```
```vue
```
```vue
{{ todo.text }}
renommer
```
---
---
url: /about/releases.md
---
# Releases {#releases}
Un journal complet des précédentes releases est disponible sur [GitHub](https://github.com/vuejs/core/blob/main/CHANGELOG.md).
## Cycle des releases {#release-cycle}
Vue n'a pas de cycle fixe pour les releases.
* Les correctifs sont publiés selon les besoins.
* Les releases mineures contiennent toujours de nouvelles fonctionnalités, avec un intervalle de temps typique allant de 3 à 6 mois. Les releases mineures passent toujours par une phase de pré-release bêta.
* Les releases majeures seront annoncées à l'avance, et passeront assez tôt par une phase de discussion et des phases de pré-release alpha/bêta.
## Versionnement sémantique - Cas limites {#semantic-versioning-edge-cases}
Les releases de Vue suivent le [versionnement sémantique](https://semver.org/) avec quelques cas limites.
### Définitions TypeScript {#typescript-definitions}
Il se peut que nous sortions des modifications incompatibles avec les définitions TypeScript entre chaque versions **mineure**. Cela est dû au fait que :
1. Parfois, TypeScript lui-même apporte des modifications incompatibles entre les versions mineures, et nous pouvons être amenés à ajuster les types pour prendre en charge les nouvelles versions de TypeScript.
2. Parfois, il peut arriver que nous devions sortir des fonctionnalités qui ne sont disponibles que dans une version récente de TypeScript, ce qui augmente la version minimale requise de TypeScript.
Si vous utilisez TypeScript, vous pouvez utiliser un gestionnaire sémantique de version qui verrouille la version mineure actuelle et effectuer une mise à niveau manuelle lorsqu'une nouvelle version mineure de Vue est publiée.
### Compatibilité du code compilé avec d'anciens moteurs {#compiled-code-compatibility-with-older-runtime}
Une version **mineur** plus récente du compilateur Vue peut générer du code qui n'est pas compatible avec le moteur Vue d'une version mineure plus ancienne. Par exemple, le code généré par le compilateur Vue 3.2 peut ne pas être totalement compatible s'il est consommé par le moteur de Vue 3.1.
Ce problème ne concerne que les auteurs de bibliothèques, car dans les applications, la version du compilateur et la version d'exécution sont toujours les mêmes. Un décalage de version ne peut se produire que si vous envoyez du code de composant Vue précompilé sous forme de package et qu'un développeur l'utilise dans un projet utilisant une version antérieure de Vue. Par conséquent, votre paquet peut avoir besoin de déclarer explicitement une version mineure minimale requise de Vue.
## Pré-releases {#pre-releases}
Les versions mineures et majeures passent généralement par une série de phases de pré-lancement : **alpha**, **bêta** et **candidate à la publication (RC)**. Le nombre et le type de versions préliminaires dépendent de l'ampleur des modifications. Par exemple, une version mineure comportant des mises à jour limitées peut ne comporter qu'une phase bêta, tandis qu'une version majeure inclura généralement les trois phases afin de permettre des tests approfondis et de recueillir les commentaires de la communauté.
Vous pouvez installer les dernières versions préliminaires depuis npm à l'aide de `npx install-vue@alpha`, `npx install-vue@beta` ou `npx install-vue@rc`. Pour tester les modifications qui ne sont pas encore incluses dans les versions préliminaires taguées, chaque commit du dépôt [vuejs/core](https://github.com/vuejs/core) est publié sous forme d'aperçu temporaire en publication continue, que vous pouvez installer à l'aide de `npx install-vue@edge`.
Les pré-releases sont destinées aux tests d'intégration et de stabilité, ainsi qu'aux utilisateurs précoces qui peuvent fournir des retours sur les fonctionnalités instables. N'utilisez pas les pré-releases en production. Elles sont considérées comme instables et peuvent contenir des modifications importante de l'une à l'autre, il faut donc toujours se référer aux versions exactes lorsque vous utilisez des pré-releases.
## Dépréciations {#deprecations}
Nous pouvons périodiquement déprécier des fonctionnalités qui sont remplacées dans les releases mineures. Les fonctionnalités dépréciées continueront à fonctionner, et seront supprimées lors de la prochaine release majeure après avoir atteint le statut de fonctionnalité dépréciée.
## RFC {#rfcs}
Les nouvelles fonctionnalités avec un potentiel d'API et des changements majeurs à Vue passeront par le processus de **demande de commentaires, ou *Request for Comments*** (RFC). Le processus RFC a pour but de fournir une voie cohérente et contrôlée pour l'introduction de nouvelles fonctionnalités dans le framework, et de donner aux utilisateurs l'opportunité de participer et d'offrir des retours dans le processus de conception.
Le processus RFC est mené dans le repo [vuejs/rfcs](https://github.com/vuejs/rfcs) sur GitHub.
## Fonctionnalités expérimentales {#experimental-features}
Certaines fonctionnalités sont livrées et documentées dans une version stable de Vue, mais marquées comme expérimentales. Les fonctionnalités expérimentales sont typiquement des fonctionnalités qui ont une discussion RFC associée avec la plupart des problèmes de conception résolus sur le papier, mais qui manquent encore de retour de cas d'utilisation réelle.
L'objectif des fonctionnalités expérimentales est de permettre aux utilisateurs de fournir un retour en les testant dans un environnement de production, sans avoir à utiliser une version instable de Vue. Les fonctionnalités expérimentales sont elles-mêmes considérées comme instables, et ne doivent être utilisées que de manière contrôlée, en sachant que la fonctionnalité peut changer entre deux versions.
---
---
url: /guide/essentials/conditional.md
---
# Rendu conditionnel {#conditional-rendering}
## `v-if` {#v-if}
La directive `v-if` est utilisée pour restituer conditionnellement un bloc. Le bloc ne sera rendu que si l'expression de la directive retourne une valeur évaluée à vrai.
```vue-html
Vue is awesome!
```
## `v-else` {#v-else}
Vous pouvez utiliser la directive `v-else` pour indiquer un bloc "sinon" lié à un `v-if`:
```vue-html
Basculer
Vue is awesome!
Oh no 😢
```
[Essayer en ligne](https://play.vuejs.org/#eNpFjkEOgjAQRa8ydIMulLA1hegJ3LnqBskAjdA27RQXhHu4M/GEHsEiKLv5mfdf/sBOxux7j+zAuCutNAQOyZtcKNkZbQkGsFjBCJXVHcQBjYUSqtTKERR3dLpDyCZmQ9bjViiezKKgCIGwM21BGBIAv3oireBYtrK8ZYKtgmg5BctJ13WLPJnhr0YQb1Lod7JaS4G8eATpfjMinjTphC8wtg7zcwNKw/v5eC1fnvwnsfEDwaha7w==)
[Essayer en ligne](https://play.vuejs.org/#eNpFjj0OwjAMha9iMsEAFWuVVnACNqYsoXV/RJpEqVOQqt6DDYkTcgRSWoplWX7y56fXs6O1u84jixlvM1dbSoXGuzWOIMdCekXQCw2QS5LrzbQLckje6VEJglDyhq1pMAZyHidkGG9hhObRYh0EYWOVJAwKgF88kdFwyFSdXRPBZidIYDWvgqVkylIhjyb4ayOIV3votnXxfwrk2SPU7S/PikfVfsRnGFWL6akCbeD9fLzmK4+WSGz4AA5dYQY=)
Un élément `v-else` doit immédiatement suivre un élément `v-if` ou un élément `v-else-if` sinon il ne sera pas reconnu.
## `v-else-if` {#v-else-if}
Le `v-else-if`, comme son nom l'indique, sert de bloc "else if" lié à un `v-if`. Il peut également être enchaîné plusieurs fois :
```vue-html
A
B
C
Not A/B/C
```
Similaire à `v-else`, un bloc `v-else-if` doit immédiatement suivre un bloc `v-if` ou `v-else-if`.
## `v-if` avec `` {#v-if-on-template}
Puisque `v-if` est une directive, elle doit être attachée à un seul élément. Mais que se passe-t-il si nous voulons basculer plus d'un élément ? Dans ce cas, nous pouvons utiliser `v-if` sur un élément ``, qui sert de conteneur invisible. Le résultat du rendu final n'inclura pas l'élément ``.
```vue-html
Title
Paragraph 1
Paragraph 2
```
`v-else` et `v-else-if` peuvent également être utilisées dans ``.
## `v-show` {#v-show}
Une autre option pour afficher conditionnellement un élément est la directive `v-show`. L'utilisation est sensiblement la même :
```vue-html
Hello!
```
La différence est qu'un élément avec `v-show` sera toujours rendu et restera dans le DOM; `v-show` bascule uniquement la propriété CSS `display` de l'élément.
`v-show` ne prend pas en charge l'élément ``, et ne fonctionne pas avec `v-else`.
## `v-if` vs. `v-show` {#v-if-vs-v-show}
`v-if` est un rendu conditionnel "réel" car il garantit que les écouteurs d'événements et les composants enfants à l'intérieur du bloc conditionnel sont correctement détruits et recréés lors des basculements.
`v-if` fonctionne également **à la volée** : si la condition est fausse lors du rendu initial, elle ne fera rien - le bloc conditionnel ne sera rendu que lorsque la condition deviendra vraie pour la première fois.
En comparaison, `v-show` est beaucoup plus simple - l'élément est toujours rendu quelle que soit la condition initiale, avec un basculement basé sur du CSS.
De manière générale, `v-if` a des coûts de basculement plus élevés tandis que `v-show` a des coûts de rendu initiaux plus élevés. Préférez donc `v-show` si vous avez besoin de basculer quelque chose très souvent, et préférez `v-if` si la condition est peu susceptible de changer à l'exécution.
## `v-if` avec `v-for` {#v-if-with-v-for}
Lorsque `v-if` et `v-for` sont toutes les deux utilisées sur le même élément, `v-if` sera évaluée en premier. Voir le [guide de rendu de liste](list#v-for-with-v-if) pour plus de détails.
::: warning Note
Il n'est **pas** recommandé d'utiliser `v-if` et `v-for` sur le même élément en raison de la priorité implicite. Reportez-vous au [guide de rendu de liste](list#v-for-with-v-if) pour plus de détails.
:::
---
---
url: /guide/scaling-up/ssr.md
---
# Rendu côté serveur (SSR) {#server-side-rendering-ssr}
## Vue d'ensemble {#overview}
### Qu'est-ce que le SSR ? {#what-is-ssr}
Vue.js est un framework pour développer des applications côté client avec des composants qui produisent et manipulent le DOM. Il peut également rendre les composants en HTML côté serveur et les hydrater en une application interactive côté client.
Une application Vue côté serveur peut être "isomorphe" ou "universelle", avec la majorité du code qui s'exécute sur le serveur **et** le client.
### Pourquoi le SSR ? {#why-ssr}
L'avantage du SSR par rapport à une application monopage SPA côté client :
* **Temps d'affichage plus rapide** : cela est plus important sur une connexion internet ou sur des périphériques lents. Le rendu côté serveur permet qu'une page soit rendue plus rapidement car elle n'a pas besoin d'attendre le téléchargement et l'exécution du JavaScript. La récupération des données se fait également côté serveur, ce qui peut améliorer la vitesse de connexion à la base de données. Cela peut entraîner une amélioration de l'expérience utilisateur et des métriques [Core Web Vitals](https://web.dev/vitals/), en particulier pour les applications où le temps d'affichage est important pour le taux de conversion.
* **Modèle mental unifié** : vous pouvez utiliser le même langage et le même modèle mental déclaratif orienté composant pour développer votre application entière, au lieu de sauter sans arrêt entre un système de modèle de backend et un framework frontend.
* **Meilleur référencement** : les robots d'indexation de moteur de recherche verront directement la page entièrement rendue.
:::tip
Les moteurs de recherche, par exemple Google et Bing, peuvent indexer correctement les applications JavaScript synchronisées. Si l'application utilise du contenu chargé de manière asynchrone, le rendu côté serveur peut être nécessaire pour un bon référencement.
:::
Il y a aussi des compromis à considérer lors de l'utilisation du SSR :
* Contraintes de développement. Le code spécifique à un navigateur ne peut être utilisé que dans certains hooks de cycle de vie, certaines bibliothèques externes peuvent nécessiter un traitement spécial pour fonctionner dans une application SSR.
* Configuration de build et exigences de déploiement plus complexes. Contrairement à une SPA entièrement statique qui peut être déployée sur n'importe quel serveur de fichiers statiques, une application SSR nécessite un environnement où un serveur Node.js peut s'exécuter.
* Charge supplémentaire côté serveur. Le rendu d'une application dans Node.js sera plus gourmand en ressources, il faut prévoir une charge supplémentaire sur le serveur et utiliser les stratégies de mise en cache
Pensez à vos besoins en temps d'affichage avant d'utiliser SSR pour votre application, car cela peut consommer plus de CPU que les fichiers statiques. Si le temps d'affichage n'est pas crucial, SSR peut être inutile. Mais si c'est important, SSR peut améliorer les performances au chargement initial.
### SSR vs. SSG {#ssr-vs-ssg}
**La génération de site statique (SSG)**, également appelée pré-rendu, est une autre technique populaire pour construire des sites web rapides. Le rendu préalable des pages peut améliorer les performances en les rendant en une seule fois pour chaque utilisateur si les données nécessaires sont les mêmes. Les pages sont alors générées et servies sous forme de fichiers HTML statiques.
SSG conserve les mêmes caractéristiques de performance que les applications SSR : il offre une excellente performance en termes de délai de mise à disposition du contenu. De plus, il est moins cher et plus facile à déployer que les applications SSR parce que le résultat est un HTML statique avec des assets. SSG ne peut être appliqué qu'aux pages fournissant des données statiques, c'est-à-dire des données qui sont connues au moment de la création et qui ne peuvent pas changer entre les requêtes. Chaque fois que les données changent, un nouveau déploiement est nécessaire.
Si vous envisagez l'utilisation du SSR uniquement pour améliorer le référencement (SEO) d'un petit nombre de pages marketing (par exemple, `/`, `/about`, `/contact`, etc.), alors vous voulez probablement du SSG au lieu du SSR. Le SSG convient aux sites web de contenu, tels que les blogs et les sites de documentation. Il est utilisé pour générer des sites web statiques, comme ce site que vous lisez maintenant qui est créé avec [VitePress](https://vitepress.dev/).
## Tutoriel de base {#basic-tutorial}
### Rendu d'une application {#rendering-an-app}
Jetons un coup d'œil à l'exemple le plus simple du SSR de Vue en action.
1. Créez un nouveau répertoire et `cd` à l'intérieur
2. Exécutez `npm init -y`
3. Ajoutez `"type": "module"` dans `package.json` pour que Node.js fonctionne en [Mode modules ES](https://nodejs.org/api/esm.html#modules-ecmascript-modules).
4. Exécutez `npm install vue`
5. Créez un fichier `example.js` :
```js
// cela fonctionne en Node.js sur le serveur.
import { createSSRApp } from 'vue'
// L'API de rendu de serveur de Vue est exposée sous `vue/server-renderer`.
import { renderToString } from 'vue/server-renderer'
const app = createSSRApp({
data: () => ({ count: 1 }),
template: `{{ count }} `
})
renderToString(app).then((html) => {
console.log(html)
})
```
Après, lancez :
```sh
> node example.js
```
Cela devrait retourner :
```
1
```
La fonction [`renderToString()`](/api/ssr#rendertostring) rend une application Vue en HTML et renvoie une Promise avec le rendu. Il peut également être rendu en continu avec l'API de stream [Node.js Stream API](https://nodejs.org/api/stream.html) ou [Web Streams API](https://developer.mozilla.org/fr/docs/Web/API/Streams_API). Voir la [référence de l'API SSR](/api/ssr) pour plus d'informations.
Nous utilisons [`express`](https://expressjs.com/) pour inclure le code Vue SSR dans une page HTML complète sur le serveur :
* Lancez `npm install express`
* Créez le fichier `server.js` suivant :
```js
import express from 'express'
import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
const server = express()
server.get('/', (req, res) => {
const app = createSSRApp({
data: () => ({ count: 1 }),
template: `{{ count }} `
})
renderToString(app).then((html) => {
res.send(`
Vue SSR Example
${html}
`)
})
})
server.listen(3000, () => {
console.log('ready')
})
```
Enfin, exécutez `node server.js` et visitez `http://localhost:3000`. Vous devriez voir la page fonctionner avec le bouton.
[Essayez-le sur StackBlitz](https://stackblitz.com/fork/vue-ssr-example-basic?file=index.js)
### Hydratation des clients {#client-hydration}
Si vous cliquez sur le bouton, vous verrez que le nombre ne change pas. L'HTML est complètement statique côté client car nous n'avons pas chargé Vue dans le navigateur.
Pour rendre l'application côté client interactive, Vue doit effectuer l'étape de l'**hydratation**. Pendant l'hydratation, il crée la même application Vue qui a été exécutée sur le serveur, associe chaque composant aux nœuds DOM qu'il doit contrôler et attache les écouteurs d'événements du DOM.
Pour monter une application en mode hydratation, nous devons utiliser [`createSSRApp()`](/api/application#createssrapp) au lieu de `createApp()` :
```js{2}
// cela fonctionne dans le navigateur.
import { createSSRApp } from 'vue'
const app = createSSRApp({
// ...même application que sur le serveur
})
// Le montage d'une application SSR sur le client suppose
// que le HTML a été pré-rendu et qu'il effectuera une
// hydratation au lieu de monter de nouveaux nœuds du DOM.
app.mount('#app')
```
### Structure du code {#code-structure}
Remarquez que nous devons réutiliser la même implémentation d'application côté serveur. C'est là que nous devons commencer à réfléchir à la structure du code dans une application SSR - comment partager le même code d'application entre le serveur et le client ?
Ici, nous allons démontrer la configuration la plus simple. Tout d'abord, divisons la logique de création d'application en un fichier dédié, `app.js`:
```js [app.js]
// (partagé entre le serveur et le client)
import { createSSRApp } from 'vue'
export function createApp() {
return createSSRApp({
data: () => ({ count: 1 }),
template: `{{ count }} `
})
}
```
Ce fichier et ses dépendances sont partagés entre le serveur et le client - nous les appelons **code universel**. Il y a un certain nombre de choses à prendre en compte lors de la rédaction du code universel, nous allons le [voir ci-dessous](#writing-ssr-friendly-code).
Notre entrée client importe le code universel, crée l'application et effectue le montage :
```js [client.js]
import { createApp } from './app.js'
createApp().mount('#app')
```
Et le serveur utilise la même logique de création d'application dans le gestionnaire de demande :
```js{2,5} [server.js]
// (code non pertinent omis)
import { createApp } from './app.js'
server.get('/', (req, res) => {
const app = createApp()
renderToString(app).then(html => {
// ...
})
})
```
De plus, pour charger les fichiers client dans le navigateur, nous devons également :
1. Servir les fichiers client en ajoutant `server.use(express.static('.'))` dans `server.js`.
2. Charger l'entrée client en ajoutant `` au fichier HTML.
3. Prendre en charge l'utilisation comme `import * from 'vue'` dans le navigateur en ajoutant [Import Map](https://github.com/WICG/import-maps) au fichier HTML.
[Essayez l'exemple complété sur StackBlitz](https://stackblitz.com/fork/vue-ssr-example?file=index.js). Le bouton est maintenant interactif !
## Solutions de haut niveau {#higher-level-solutions}
Pour une application SSR en production, plusieurs considérations supplémentaires doivent être prises en compte :
* Prendre en charge les SFC Vue et d'autres exigences de l'étape de build. En fait, nous aurons besoin de coordonner deux builds pour la même application : un pour le client et un pour le serveur.
:::tip
Les composants Vue sont compilés différemment en SSR : les templates compilés sont compilés en chaînes, par rapport à des fonctions de rendu de DOM virtuel, pour une performance accrue.
:::
* Dans le gestionnaire de requête du serveur, afficher le HTML avec les liens corrects des ressources clientes et autres ressources optimisées. Il peut également être nécessaire de basculer entre le mode SSR et SSG, ou même de mélanger les deux dans la même application.
* Gestion du routage, de la récupération de données et des stores de gestion d'état de manière universelle.
Une implémentation complète serait assez complexe et dépend de la chaîne d'outils de build que vous avez choisie. Par conséquent, nous vous recommandons fortement d'adopter une solution plus élevée et orientée afin d'abstraire la complexité pour vous. Ci-dessous, nous présenterons quelques solutions SSR recommandées dans l'écosystème Vue.
### Nuxt {#nuxt}
[Nuxt](https://nuxt.com/) est une plateforme Vue simplifiée pour développer des applications universelles et peut être utilisée comme générateur de site statique. Nous vous recommandons fortement de l'essayer.
### Quasar {#quasar}
[Quasar](https://quasar.dev) est une plateforme basée sur Vue qui vous permet de développer des applications pour plusieurs plateformes (SSR, SPA, PWA, mobile, bureau, extension de navigateur) avec un seul code de base. Il fournit également des composants d'interface utilisateur conformes à Material Design.
### Vite SSR {#vite-ssr}
Vite fournit [un support natif pour le rendu côté serveur de Vue](https://vite.dev/guide/ssr.html), mais il est intentionnellement de bas niveau. Si vous souhaitez utiliser directement avec Vite, consultez [vite-plugin-ssr](https://vite-plugin-ssr.com/), un plugin communautaire qui fait abstraction de nombreux détails complexes pour vous.
Vous pouvez également trouver un exemple de projet Vue + Vite SSR en utilisant une configuration manuelle ici, qui peut servir de base pour le build. Notez que ceci n'est recommandé que si vous avez de l'expérience avec SSR / outils de build et que vous souhaitez avoir un contrôle complet sur l'architecture de haut niveau.
## Écrire du code SSR propre {#writing-ssr-friendly-code}
Indépendamment de votre configuration de build ou de votre choix de framework de haut niveau, il existe des principes qui s'appliquent à toutes les applications Vue SSR.
### Réactivité sur le serveur {#reactivity-on-the-server}
Pendant le SSR, chaque URL requêtée correspond à un état souhaité de notre application. Il n'y a pas d'interaction utilisateur et aucune mise à jour du DOM, donc la réactivité n'est pas nécessaire sur le serveur. Par défaut, la réactivité est désactivée pendant le SSR pour une meilleure performance.
### Les hooks du cycle de vie du composant {#component-lifecycle-hooks}
Vu qu'il n'y a pas de mises à jour dynamiques, les hooks de cycle de vie tels que `mounted``onMounted` ou `updated``onUpdated` ne seront **PAS** appelés pendant le SSR et ne seront exécutés que côté client. Les seuls hooks qui sont appelés pendant le SSR sont `beforeCreate` et `created`
Vous devriez éviter le code qui produit des effets de bord qui nécessitent un nettoyage dans `beforeCreate` et `created``setup()` ou dans la portée de `
Home |
About |
Broken Link
```
[Essayer en ligne](https://play.vuejs.org/#eNptUk1vgkAQ/SsTegAThZp4MmhikzY9mKanXkoPWxjLRpgly6JN1P/eWb5Eywlm572ZN2/m5GyKwj9U6CydsIy1LAyUaKpiHZHMC6UNnEDjbgqxyovKYAIX2GmVg8sktwe9qhzbdz+wga15TW++VWX6fB3dAt6UeVEVJT2me2hhEcWKSgOamVjCCk4RAbiBu6xbT5tI2ML8VDeI6HLlxZXWSOZdmJTJPJB3lJSoo5+pWBipyE9FmU4soU2IJHk+MGUrS4OE2nMtIk4F/aA7BW8Cq3WjYlDbP4isQu4wVp0F1Q1uFH1IPDK+c9cb1NW8B03tyJ//uvhlJmP05hM4n60TX/bb2db0CoNmpbxMDgzmRSYMcgQQCkjZhlXkPASRs7YmhoFYw/k+WXvKiNrTcQgpmuFv7ZOZFSyQ4U9a7ZFgK2lvSTXFDqmIQbCUJTMHFkQOBAwKg16kM3W6O7K3eSs+nbeK+eee1V/XKK0dY4Q3vLhR6uJxMUK8/AFKaB6k)
```vue
Home |
About |
Broken Link
```
[Essayer en ligne](https://play.vuejs.org/#eNptUstO6zAQ/ZVR7iKtVJKLxCpKK3Gli1ggxIoNZmGSKbFoxpEzoUi0/87YeVBKNonHPmfOmcdndN00yXuHURblbeFMwxtFpm6sY7i1NcLW2RriJPWBB8bT8/WL7Xh6D9FPwL3lG9tROWHGiwGmqLDUMjhhYgtr+FQEEKdxFqRXfaR9YrkKAoqOnocfQaDEre523PNKzXqx7M8ADrlzNEYAReccEj9orjLYGyrtPtnZQrOxlFS6rXqgZJdPUC5s3YivMhuTDCkeDe6/dSalvognrkybnIgl7c4UuLhcwuHgS3v2/7EPvzRruRXJ7/SDU12W/98l451pGQndIvaWi0rTK8YrEPx64ymKFQOce5DOzlfs4cdlkA+NzdNpBSRgrJudZpQIINdQOdyuVfQnVdHGzydP9QYO549hXIII45qHkKUL/Ail8EUjBgX+z9k3JLgz9OZJgeInYElAkJlWmCcDUBGkAsrTyWS0isYV9bv803x1OTiWwzlrWtxZ2lDGDO90mWepV3+vZojHL3QQKQE=)
---
---
url: /guide/best-practices/security.md
---
# Sécurité {#security}
## Signalement des vulnérabilités {#reporting-vulnerabilities}
Lorsqu'une vulnérabilité est signalée, elle devient immédiatement notre principale préoccupation, et un collaborateur à temps plein se concentre pour y remédier. Pour signaler une vulnérabilité, veuillez envoyer un mail à .
Bien que la découverte de nouvelles vulnérabilités soit rare, nous recommandons également de toujours utiliser les dernières versions de Vue et de ses bibliothèques annexes officielles pour garantir que votre application reste aussi sûre que possible.
## Règle n°1: N'utilisez jamais de templates non fiables {#rule-no-1-never-use-non-trusted-templates}
La règle de sécurité la plus fondamentale lorsque vous utilisez Vue est de **ne jamais utiliser de contenu non fiable comme template de composant**. Cela équivaut à autoriser l'exécution arbitraire de JavaScript dans votre application - et pire encore, cela pourrait entraîner des failles dans le serveur si le code est exécuté pendant le rendu côté serveur. Un exemple d'une telle utilisation :
```js
Vue.createApp({
template: `` + userProvidedString + `
` // NE JAMAIS FAIRE ÇA
}).mount('#app')
```
Les templates Vue sont compilés en JavaScript, et les expressions qui y sont contenues seront exécutées dans le cadre du processus de rendu. Bien que les expressions soient évaluées par rapport à un contexte de rendu spécifique, en raison de la complexité des environnements d'exécution globaux potentiels, il n'est pas possible pour un framework comme Vue de vous protéger complètement de l'exécution potentielle de code malveillant sans risquer une dégradation critique des performances. La façon la plus simple d'éviter complètement ce genre de problèmes est de s'assurer que le contenu de vos templates Vue est toujours fiable et que vous le contrôlez totalement.
## Ce que Vue fait pour vous protéger {#what-vue-does-to-protect-you}
### Contenu HTML {#html-content}
Que vous utilisiez des templates ou des fonctions de rendu, le contenu est automatiquement échappé. Cela signifie que dans ce template :
```vue-html
{{ userProvidedString }}
```
si `userProvidedString` contient :
```js
''
```
alors il sera échappé en l'HTML suivant :
```vue-html
<script>alert("hi")</script>
```
empêchant ainsi l'injection de script. Cet échappement est effectué en utilisant les API natives du navigateur, comme `textContent`, donc une vulnérabilité ne peut exister que si le navigateur lui-même est vulnérable.
### Liaisons d'attributs {#attribute-bindings}
De même, les liaisons d'attributs dynamiques sont automatiquement échappées. Cela signifie que dans ce template :
```vue-html
hello
```
si `userProvidedString` contient :
```js
'" onclick="alert(\'hi\')'
```
alors il sera échappé en l'HTML suivant :
```vue-html
" onclick="alert('hi')
```
empêchant ainsi la fermeture de l'attribut `title` pour injecter du nouveau HTML arbitraire. Cet échappement est effectué en utilisant les API natives du navigateur, comme `setAttribute`, donc une vulnérabilité ne peut exister que si le navigateur lui-même est vulnérable.
## Dangers potentiels {#potential-dangers}
Dans toute application Web, le fait d'autoriser l'exécution de contenu non nettoyé fourni par l'utilisateur sous forme d'HTML, de CSS ou de JavaScript est potentiellement dangereux et doit donc être évité dans la mesure du possible. Il y a cependant des cas où un certain risque peut être acceptable.
Par exemple, des services tels que CodePen et JSFiddle permettent l'exécution de contenu fourni par l'utilisateur, mais dans un contexte où cela est attendu et encadré dans une certaine mesure par des iframes. Dans les cas où une fonctionnalité importante nécessite intrinsèquement un certain niveau de vulnérabilité, il appartient à votre équipe d'évaluer l'importance de cette dernière par rapport aux pires scénarios qu'elle peut apporter.
### Injection HTML {#html-injection}
Comme vous l'avez appris précédemment, Vue échappe automatiquement le contenu HTML, ce qui vous empêche d'injecter accidentellement du HTML exécutable dans votre application. Cependant, **dans les cas où vous savez que le HTML est sûr**, vous pouvez rendre le contenu HTML de manière explicite :
* En utilisant un template :
```vue-html
```
* En utilisant une fonction de rendu :
```js
h('div', {
innerHTML: this.userProvidedHtml
})
```
* En utilisant une fonction de rendu avec JSX :
```jsx
```
:::warning
Le HTML fourni par l'utilisateur ne peut jamais être considéré comme 100 % sûr, sauf s'il se trouve dans une iframe protégée enveloppée dans une sandbox ou dans une partie de l'application où seul l'utilisateur qui a écrit ce HTML peut y être exposé. En outre, permettre aux utilisateurs d'écrire leurs propres templates Vue présente des dangers similaires.
:::
### Injection d'URL {#url-injection}
Dans une URL comme celle-ci :
```vue-html
click me
```
Il existe un problème de sécurité potentiel si l'URL n'a pas été "nettoyée" pour empêcher l'exécution de JavaScript en utilisant `javascript:`. Il existe des bibliothèques telles que [sanitize-url](https://www.npmjs.com/package/@braintree/sanitize-url) pour vous aider dans cette tâche, mais attention : si vous effectuez le nettoyage des URL côté front-end, vous avez déjà un problème de sécurité. **Les URL fournies par l'utilisateur doivent toujours être nettoyées par votre backend avant même d'être enregistrées dans une base de données**. Le problème est alors évité pour *tous* les clients qui se connectent à votre API, y compris depuis les applications mobiles natives. Notez également que même avec des URL nettoyées, Vue ne peut pas vous aider à garantir qu'elles mènent à des destinations sûres.
### Injection de style {#style-injection}
Regardons cet exemple :
```vue-html
click me
```
Supposons que `sanitizedUrl` ait été nettoyée, de sorte qu'il s'agisse bien d'une véritable URL et non de JavaScript. Avec le `userProvidedStyles`, les utilisateurs malveillants peuvent toujours fournir du CSS pour "détourner le clic", par exemple en transformant le lien en une boîte transparente au-dessus du bouton "Se connecter". Ensuite, si `https://user-controlled-website.com/` est codé pour ressembler à la page de connexion de votre application, ils peuvent avoir capturé les véritables informations de connexion d'un utilisateur.
Vous pouvez peut-être imaginer comment le fait d'autoriser le contenu fourni par l'utilisateur pour un élément `
```
Pour que vos utilisateurs soient totalement à l'abri du détournement de clic, nous vous recommandons de n'autoriser le contrôle total du CSS qu'à l'intérieur d'une iframe enveloppée dans une sandbox. Par ailleurs, lorsque vous offrez un contrôle à l'utilisateur via une liaison de style, nous vous recommandons d'utiliser sa [syntaxe objet](/guide/essentials/class-and-style#binding-to-objects-1) et de n'autoriser les utilisateurs à fournir des valeurs que pour des propriétés spécifiques qu'ils peuvent contrôler en toute sécurité, comme ceci :
```vue-html
click me
```
### Injection JavaScript {#javascript-injection}
Nous déconseillons fortement de rendre un élément `
rouge
```
## `v-bind()` dans du CSS {#v-bind-in-css}
Les balises `
```
La syntaxe fonctionne avec [`
hello
```
La valeur réelle sera compilée dans une propriété personnalisée CSS hachée, afin que le CSS reste statique. La propriété personnalisée sera appliquée à l'élément racine du composant via des styles en ligne et mise à jour de manière réactive si la valeur source change.
---
---
url: /guide/components/slots.md
---
# Slots {#slots}
> Cette page suppose que vous avez déjà lu les [bases à propos des composants](/guide/essentials/component-basics). Lisez-les d'abord si vous débutez avec les composants.
## Les contenus de slot {#slot-content-and-outlet}
Nous avons appris que les composants peuvent accepter des props, qui peuvent être des valeurs JavaScript de n'importe quel type. Mais qu'en est-il du contenu du template ? Dans certains cas, nous pouvons vouloir transmettre un fragment de template à un composant enfant et laisser le composant enfant afficher le fragment dans son propre template.
Par exemple, nous pouvons avoir un composant `` qui prend en charge l'utilisation suivante :
```vue-html{2}
Click me!
```
Le template de `` ressemble à ceci :
```vue-html{2}
```
L'élément `` est un **emplacement du slot** qui indique où le **contenu du slot** fourni par le parent doit être affiché.

Et le DOM rendu final :
```html
Click me!
```
[Essayer en ligne](https://play.vuejs.org/#eNpdUdlqAyEU/ZVbQ0kLMdNsXabTQFvoV8yLcRkkjopLSQj596oTwqRvnuM9y9UT+rR2/hs5qlHjqZM2gOch2m2rZW+NC/BDND1+xRCMBuFMD9N5NeKyeNrqphrUSZdA4L1VJPCEAJrRdCEAvpWke+g5NHcYg1cmADU6cB0A4zzThmYckqimupqiGfpXILe/zdwNhaki3n+0SOR5vAu6ReU++efUajtqYGJQ/FIg5w8Wt9FlOx+OKh/nV1c4ZVNqlHE1TIQQ7xnvCN13zkTNalBSc+Jw5wiTac2H1WLDeDeDyXrJVm9LWG7uE3hev3AhHge1cYwnO200L4QljEnd1bCxB1g82UNhe+I6qQs5kuGcE30NrxeaRudzOWtkemeXuHP5tLIKOv8BN+mw3w==)
[Essayer en ligne](https://play.vuejs.org/#eNpdUdtOwzAM/RUThAbSurIbl1ImARJf0ZesSapoqROlKdo07d9x0jF1SHmIT+xzcY7sw7nZTy9Zwcqu9tqFTYW6ddYH+OZYHz77ECyC8raFySwfYXFsUiFAhXKfBoRUvDcBjhGtLbGgxNAVcLziOlVIp8wvelQE2TrDg6QKoBx1JwDgy+h6B62E8ibLoDM2kAAGoocsiz1VKMfmCCrzCymbsn/GY95rze1grja8694rpmJ/tg1YsfRO/FE134wc2D4YeTYQ9QeKa+mUrgsHE6+zC+vfjoz1Bdwqpd5iveX1rvG2R1GA0Si5zxrPhaaY98v5WshmCrerhVi+LmCxvqPiafUslXoYpq0XkuiQ1p4Ax4XQ2BSwdnuYP7p9QlvuG40JHI1lUaenv3o5w3Xvu2jOWU179oQNn5aisNMvLBvDOg==)
Avec les slots, le `` est responsable du rendu du `` externe (et de son style), tandis que le contenu interne est fourni par le composant parent.
Une autre façon de comprendre les slots consiste à les comparer aux fonctions JavaScript :
```js
// composant parent passant le contenu du slot
FancyButton('Click me!')
// FancyButton effectue le rendu du contenu du slot dans son propre template
function FancyButton(slotContent) {
return `
${slotContent}
`
}
```
Le contenu du slot ne se limite pas à du texte. Il peut s'agir de n'importe quel contenu de template valide. Par exemple, nous pouvons passer plusieurs éléments, voire d'autres composants :
```vue-html
Click me!
```
[Essayer en ligne](https://play.vuejs.org/#eNp1UmtOwkAQvspQYtCEgrx81EqCJibeoX+W7bRZaHc3+1AI4QyewH8ewvN4Aa/gbgtNIfFf5+vMfI/ZXbCQcvBmMYiCWFPFpAGNxsp5wlkphTLwQjjdPlljBIdMiRJ6g2EL88O9pnnxjlqU+EpbzS3s0BwPaypH4gqDpSyIQVcBxK3VFQDwXDC6hhJdlZi4zf3fRKwl4aDNtsDHJKCiECqiW8KTYH5c1gEnwnUdJ9rCh/XeM6Z42AgN+sFZAj6+Ux/LOjFaEK2diMz3h0vjNfj/zokuhPFU3lTdfcpShVOZcJ+DZgHs/HxtCrpZlj34eknoOlfC8jSCgnEkKswVSRlyczkZzVLM+9CdjtPJ/RjGswtX3ExvMcuu6mmhUnTruOBYAZKkKeN5BDO5gdG13FRoSVTOeAW2xkLPY3UEdweYWqW9OCkYN6gctq9uXllx2Z09CJ9dJwzBascI7nBYihWDldUGMqEgdTVIq6TQqCEMfUpNSD+fX7/fH+3b7P8AdGP6wA==)
[Essayer en ligne](https://play.vuejs.org/#eNptUltu2zAQvMpGQZEWsOzGiftQ1QBpgQK9g35oaikwkUiCj9aGkTPkBPnLIXKeXCBXyJKKBdoIoA/tYGd3doa74tqY+b+ARVXUjltp/FWj5GC09fCHKb79FbzXCoTVA5zNFxkWaWdT8/V/dHrAvzxrzrC3ZoBG4SYRWhQs9B52EeWapihU3lWwyxfPDgbfNYq+ejEppcLjYHrmkSqAOqMmAOB3L/ktDEhV4+v8gMR/l1M7wxQ4v+3xZ1Nw3Wtb8S1TTXG1H3cCJIO69oxc5mLUcrSrXkxSi1lxZGT0//CS9Wg875lzJELE/nLto4bko69dr31cFc8auw+3JHvSEfQ7nwbsHY9HwakQ4kes14zfdlYH1VbQS4XMlp1lraRMPl6cr1rsZnB6uWwvvi9hufpAxZfLryjEp5GtbYs0TlGICTCsbaXqKliZDZx/NpuEDsx2UiUwo5VxT6Dkv73BPFgXxRktlUdL2Jh6OoW8O3pX0buTsoTgaCNQcDjoGwk3wXkQ2tJLGzSYYI126KAso0uTSc8Pjy9P93k2d6+NyRKa)
En utilisant des slots, notre `` est plus flexible et réutilisable. Nous pouvons maintenant l'utiliser à différents endroits avec un contenu différent, mais tous avec le même style appliqué.
Le mécanisme de slot des composants Vue est inspiré de l'[élément natif Web Component ``](https://developer.mozilla.org/fr/docs/Web/HTML/Element/slot), mais avec des fonctionnalités supplémentaires que nous verrons plus tard.
## Portée du rendu {#render-scope}
Le contenu du slot a accès à la portée des données du composant parent, car il est défini dans le parent. Par exemple :
```vue-html
{{ message }}
{{ message }}
```
Ici, les deux interpolations `{{ message }}` rendront le même contenu.
Le contenu du slot **n'a pas** accès aux données du composant enfant. Les expressions dans les templates Vue ne peuvent accéder qu'à la portée de déclaration dans laquelle elles sont définies, conformément à la portée lexicale de JavaScript. Autrement dit :
> Les expressions présentes dans le template du parent n'ont accès qu'à la portée du parent ; les expressions dans le template de l'enfant n'ont accès qu'à la portée du composant enfant.
## Contenu par défaut {#fallback-content}
Il existe des cas où il est utile de spécifier un contenu par défaut pour un slot, à rendre uniquement lorsqu'aucun contenu n'est fourni. Par exemple, dans un composant `` :
```vue-html
```
Nous pourrions souhaiter que le texte "Submit" soit rendu à l'intérieur du `` si le parent n'a fourni aucun contenu pour le slot. Pour faire de "Submit" le contenu par défaut, nous pouvons le placer entre les balises `` :
```vue-html{3}
Submit
```
Maintenant, lorsque nous utilisons `` dans un composant parent, en ne fournissant aucun contenu pour le slot :
```vue-html
```
Cela rendra le contenu par défaut, "Submit":
```html
Submit
```
Mais si nous fournissons le contenu :
```vue-html
Save
```
Alors, le contenu fourni sera affiché à la place :
```html
Save
```
[Essayer en ligne](https://play.vuejs.org/#eNp1kMsKwjAQRX9lzMaNbfcSC/oL3WbT1ikU8yKZFEX8d5MGgi2YVeZxZ86dN7taWy8B2ZlxP7rZEnikYFuhZ2WNI+jCoGa6BSKjYXJGwbFufpNJfhSaN1kflTEgVFb2hDEC4IeqguARpl7KoR8fQPgkqKpc3Wxo1lxRWWeW+Y4wBk9x9V9d2/UL8g1XbOJN4WAntodOnrecQ2agl8WLYH7tFyw5olj10iR3EJ+gPCxDFluj0YS6EAqKR8mi9M3Td1ifLxWShcU=)
[Essayer en ligne](https://play.vuejs.org/#eNp1UEEOwiAQ/MrKxYu1d4Mm+gWvXChuk0YKpCyNxvh3lxIb28SEA8zuDDPzEucQ9mNCcRAymqELdFKu64MfCK6p6Tu6JCLvoB18D9t9/Qtm4lY5AOXwMVFu2OpkCV4ZNZ51HDqKhwLAQjIjb+X4yHr+mh+EfbCakF8AclNVkCJCq61ttLkD4YOgqsp0YbGesJkVBj92NwSTIrH3v7zTVY8oF8F4SdazD7ET69S5rqXPpnigZ8CjEnHaVyInIp5G63O6XIGiIlZMzrGMd8RVfR0q4lIKKV+L+srW+wNTTZq3)
## Slots nommés {#named-slots}
Il y a des moments où il est utile d'avoir plusieurs emplacements de slot dans un seul composant. Par exemple, dans un composant `` avec le template suivant :
```vue-html
```
Dans ces cas, l'élément `` a un attribut spécial, `name`, qui peut être utilisé pour attribuer un ID unique à différents slots afin que vous puissiez déterminer où le contenu doit être affiché :
```vue-html
```
Une balise `` sans attribut `name` porte implicitement le nom "default".
Dans un composant parent utilisant ``, nous avons besoin d'un moyen de transmettre plusieurs fragments de contenu de slot, chacun ciblant un emplacement de slot différent. C'est là qu'interviennent les **slots nommés**.
Pour passer un slot nommé, nous devons utiliser un élément `` avec la directive `v-slot`, puis passer le nom du slot comme argument à `v-slot` :
```vue-html
```
`v-slot` a un raccourci dédié `#`, donc `` peut être raccourci en juste ``. Pensez-y comme "rendre ce fragment de template dans le slot 'header' du composant enfant".

Voici le code transmettant le contenu des trois slots à `` en utilisant la syntaxe abrégée :
```vue-html
Here might be a page title
A paragraph for the main content.
And another one.
Here's some contact info
```
Lorsqu'un composant accepte à la fois un emplacement par défaut et des emplacements nommés, tous les nœuds de niveau supérieur non `` sont implicitement traités comme du contenu pour le slot par défaut. Donc ce qui précède peut aussi s'écrire :
```vue-html
Here might be a page title
A paragraph for the main content.
And another one.
Here's some contact info
```
Désormais, tout ce qui se trouve à l'intérieur des éléments `` sera transmis aux slots correspondants. Le rendu HTML final sera :
```html
Here might be a page title
A paragraph for the main content.
And another one.
```
[Essayer en ligne](https://play.vuejs.org/#eNp9UsFuwjAM/RWrHLgMOi5o6jIkdtphn9BLSF0aKU2ixEVjiH+fm8JoQdvRfu/5xS8+ZVvvl4cOsyITUQXtCSJS5zel1a13geBdRvyUR9cR1MG1MF/mt1YvnZdW5IOWVVwQtt5IQq4AxI2cau5ccZg1KCsMlz4jzWrzgQGh1fuGYIcgwcs9AmkyKHKGLyPykcfD1Apr2ZmrHUN+s+U5Qe6D9A3ULgA1bCK1BeUsoaWlyPuVb3xbgbSOaQGcxRH8v3XtHI0X8mmfeYToWkxmUhFoW7s/JvblJLERmj1l0+T7T5tqK30AZWSMb2WW3LTFUGZXp/u8o3EEVrbI9AFjLn8mt38fN9GIPrSp/p4/Yoj7OMZ+A/boN9KInPeZZpAOLNLRDAsPZDgN4p0L/NQFOV/Ayn9x6EZXMFNKvQ4E5YwLBczW6/WlU3NIi6i/sYDn5Qu2qX1OF51MsvMPkrIEHg==)
[Essayer en ligne](https://play.vuejs.org/#eNp9UkFuwjAQ/MoqHLiUpFxQlaZI9NRDn5CLSTbEkmNb9oKgiL934wRwQK3ky87O7njGPicba9PDHpM8KXzlpKV1qWVnjSP4FB6/xcnsCRpnOpin2R3qh+alBig1HgO9xkbsFcG5RyvDOzRq8vkAQLSury+l5lNkN1EuCDurBCFXAMWdH2pGrn2YtShqdCPOnXa5/kKH0MldS7BFEGDFDoEkKSwybo8rskjjaevo4L7Wrje8x4mdE7aFxjiglkWE1GxQE9tLi8xO+LoGoQ3THLD/qP2/dGMMxYZs8DP34E2HQUxUBFI35o+NfTlJLOomL8n04frXns7W8gCVEt5/lElQkxpdmVyVHvP2yhBo0SHThx5z+TEZvl1uMlP0oU3nH/kRo3iMI9Ybes960UyRsZ9pBuGDeTqpwfBAvn7NrXF81QUZm8PSHjl0JWuYVVX1PhAqo4zLYbZarUak4ZAWXv5gDq/pG3YBHn50EEkuv5irGBk=)
Encore une fois, cela peut vous aider à mieux comprendre les slots nommés en utilisant l'analogie avec une fonction JavaScript :
```js
// passage de plusieurs fragments de slot avec des noms différents
BaseLayout({
header: `...`,
default: `...`,
footer: `...`
})
// les affiche à différents emplacements
function BaseLayout(slots) {
return `
${slots.default}
`
}
```
## Slots conditionnels {#conditional-slots}
Il arrive que l'on veuille rendre quelque chose en fonction de la transmission ou non d'un contenu à un slot.
Vous pouvez utiliser la propriété [$slots](/api/component-instance.html#slots) en combinaison avec un [v-if](/guide/essentials/conditional.html#v-if) pour y parvenir.
Dans l'exemple ci-dessous, nous définissons un composant Card avec trois slots conditionnels : `header`, `footer` et `default`.
Lorsque l'en-tête / le pied de page / du texte par défaut est présent, nous voulons l'envelopper pour lui donner un style supplémentaire :
```vue-html
```
[Essayer en ligne](https://play.vuejs.org/#eNqVVMtu2zAQ/BWCLZBLIjVoTq4aoA1yaA9t0eaoCy2tJcYUSZCUKyPwv2dJioplOw4C+EDuzM4+ONYT/aZ1tumBLmhhK8O1IxZcr29LyTutjCN3zNRkZVRHLrLcXzz9opRFHvnIxIuDTgvmAG+EFJ4WTnhOCPnQAqvBjHFE2uvbh5Zbgj/XAolwkWN4TM33VI/UalixXvjyo5yeqVVKOpCuyP0ob6utlHL7vUE3U4twkWP4hJq/jiPP4vSSOouNrHiTPVolcclPnl3SSnWaCzC/teNK2pIuSEA8xoRQ/3+GmDM9XKZ41UK1PhF/tIOPlfSPAQtmAyWdMMdMAy7C9/9+wYDnCexU3QtknwH/glWi9z1G2vde1tj2Hi90+yNYhcvmwd4PuHabhvKNeuYu8EuK1rk7M/pLu5+zm5BXyh1uMdnOu3S+95pvSCWYtV9xQcgqaXogj2yu+AqBj1YoZ7NosJLOEq5S9OXtPZtI1gFSppx8engUHs+vVhq9eVhq9ORRrXdpRyseSqfo6SmmnONK6XTw9yis24q448wXSG+0VAb3sSDXeiBoDV6TpWDV+ktENatrdMGCfAoBfL1JYNzzpINJjVFoJ9yKUKho19ul6OFQ6UYPx1rjIpPYeXIc/vXCgjetawzbni0dPnhhJ3T3DMVSruI=)
## Noms de slot dynamiques {#dynamic-slot-names}
[Les arguments de directive dynamique](/guide/essentials/template-syntax.md#dynamic-arguments) fonctionnent également sur `v-slot`, permettant la définition de noms de slots dynamiques :
```vue-html
...
...
```
Notez que l'expression est soumise aux [contraintes de syntaxe](/guide/essentials/template-syntax.md#dynamic-argument-syntax-constraints) des arguments de directive dynamiques.
## Scoped Slots {#scoped-slots}
Comme indiqué dans [Portée du rendu](#render-scope), le contenu du slot n'a pas accès à l'état dans le composant enfant.
Cependant, il existe des cas où il peut être utile que le contenu d'un slot puisse utiliser des données provenant à la fois de la portée du parent et de la portée de l'enfant. Pour y parvenir, nous avons besoin d'un moyen pour l'enfant de transmettre des données à un slot pour son affichage.
En fait, nous pouvons faire exactement cela - nous pouvons transmettre des attributs à un emplacement de slot comme on transmettrait des props à un composant :
```vue-html
```
La réception des props de slot est un peu différente lorsque vous utilisez un seul slot par défaut par rapport à l'utilisation de slots nommés. Nous allons d'abord montrer comment recevoir des props en utilisant un seul slot par défaut, en utilisant `v-slot` directement sur la balise du composant enfant :
```vue-html
{{ slotProps.text }} {{ slotProps.count }}
```

[Essayer en ligne](https://play.vuejs.org/#eNp9kMEKgzAMhl8l9OJlU3aVOhg7C3uAXsRlTtC2tFE2pO++dA5xMnZqk+b/8/2dxMnadBxQ5EL62rWWwCMN9qh021vjCMrn2fBNoya4OdNDkmarXhQnSstsVrOOC8LedhVhrEiuHca97wwVSsTj4oz1SvAUgKJpgqWZEj4IQoCvZm0Gtgghzss1BDvIbFkqdmID+CNdbbQnaBwitbop0fuqQSgguWPXmX+JePe1HT/QMtJBHnE51MZOCcjfzPx04JxsydPzp2Szxxo7vABY1I/p)
[Essayer en ligne](https://play.vuejs.org/#eNqFkNFqxCAQRX9l8CUttAl9DbZQ+rzQD/AlJLNpwKjoJGwJ/nvHpAnusrAg6FzHO567iE/nynlCUQsZWj84+lBmGJ31BKffL8sng4bg7O0IRVllWnpWKAOgDF7WBx2em0kTLElt975QbwLkhkmIyvCS1TGXC8LR6YYwVSTzH8yvQVt6VyJt3966oAR38XhaFjjEkvBCECNcia2d2CLyOACZQ7CDrI6h4kXcAF7lcg+za6h5et4JPdLkzV4B9B6RBtOfMISmxxqKH9TarrGtATxMgf/bDfM/qExEUCdEDuLGXAmoV06+euNs2JK7tyCrzSNHjX9aurQf)
Les props passés au slot par l'enfant sont disponibles en tant que valeur de la directive `v-slot` correspondante, accessible par les expressions à l'intérieur du slot.
Vous pouvez considérer un "scoped slot" comme une fonction transmise au composant enfant. Le composant enfant l'appelle ensuite, en passant des props comme arguments :
```js
MyComponent({
// passage du slot par défaut, mais en tant que fonction
default: (slotProps) => {
return `${slotProps.text} ${slotProps.count}`
}
})
function MyComponent(slots) {
const greetingMessage = 'hello'
return `${
// appel de la fonction slot avec les props !
slots.default({ text: greetingMessage, count: 1 })
}
`
}
```
En fait, c'est très proche de la façon dont les "scoped slots" sont compilés et de la façon dont vous utiliseriez les "scoped slots" dans les [fonctions de rendu](/guide/extras/render-function) manuelles.
Remarquez comment `v-slot="slotProps"` correspond à la signature de la fonction slot. Tout comme avec les arguments de fonction, nous pouvons utiliser la déstructuration dans `v-slot` :
```vue-html
{{ text }} {{ count }}
```
### Scoped slots nommés {#named-scoped-slots}
Les Scoped slots nommés fonctionnent de la même manière - les props du slot sont accessibles en tant que valeur de la directive `v-slot` : `v-slot:name="slotProps"`. Lorsque vous utilisez le raccourci, cela ressemble à ceci :
```vue-html
{{ headerProps }}
{{ defaultProps }}
{{ footerProps }}
```
Passer des props à un slot nommé :
```vue-html
```
Notez que l'attribut `name` d'un slot ne sera pas inclus dans les props car il est réservé - donc le `headerProps` résultant serait `{ message: 'hello' }`.
Si vous mélangez des slots nommés avec des "scoped slots" par défaut, vous devez utiliser une balise `` explicite pour le slot par défaut. Tenter de placer la directive `v-slot` directement sur le composant entraînera une erreur de compilation. Ceci afin d'éviter toute ambiguïté sur la portée des props du slot par défaut. Par exemple :
```vue-html
```
```vue-html
{{ message }}
{{ message }}
```
L'utilisation explicite d'une balise `` pour le slot par défaut aide à indiquer clairement que la prop `message` n'est pas disponible dans l'autre slot :
```vue-html
{{ message }}
Here's some contact info
```
### Exemple Fancy List {#fancy-list-example}
Vous vous demandez peut-être quel serait un bon cas d'utilisation pour les scoped slots. Voici un exemple : imaginez un composant `` qui affiche une liste d'éléments - il peut encapsuler la logique de chargement des données distantes, utiliser les données pour afficher une liste, ou même des fonctionnalités avancées comme la pagination ou le défilement infini. Cependant, nous voulons qu'il soit flexible avec l'apparence de chaque élément et laisse la définition du style de chaque élément au composant parent qui le consomme. Ainsi, l'utilisation souhaitée peut ressembler à ceci :
```vue-html
{{ body }}
by {{ username }} | {{ likes }} likes
```
Dans ``, nous pouvons afficher le même `` plusieurs fois avec différentes données (notez que nous utilisons `v-bind` pour passer un objet en tant que props du slot) :
```vue-html
```
[Essayer en ligne](https://play.vuejs.org/#eNqFU2Fv0zAQ/StHJtROapNuZTBCNwnQQKBpTGxCQss+uMml8+bYlu2UlZL/zjlp0lQa40sU3/nd3Xv3vA7eax0uSwziYGZTw7UDi67Up4nkhVbGwScm09U5tw5yowoYhFEX8cBBImdRgyQMHRwWWjCHdAKYbdFM83FpxEkS0DcJINZoxpotkCIHkySo7xOixcMep19KrmGustUISotGsgJHIPgDWqg6DKEyvoRUMGsJ4HG9HGX16bqpAlU1izy5baqDFegYweYroMttMwLAHx/Y9Kyan36RWUTN2+mjXfpbrei8k6SjdSuBYFOlMaNI6AeAtcflSrqx5b8xhkl4jMU7H0yVUCaGvVeH8+PjKYWqWnpf5DQYBTtb+fc612Awh2qzzGaBiUyVpBVpo7SFE8gw5xIv/Wl4M9gsbjCCQbuywe3+FuXl9iiqO7xpElEEhUofKFQo2mTGiFiOLr3jcpFImuiaF6hKNxzuw8lpw7kuEy6ZKJGK3TR6NluLYXBVqwRXQjkLn0ueIc3TLonyZ0sm4acqKVovKIbDCVQjGsb1qvyg2telU4Yzz6eHv6ARBWdwjVqUNCbbFjqgQn6aW1J8RKfJhDg+5/lStG4QHJZjnpO5XjT0BMqFu+uZ81yxjEQJw7A1kOA76FyZjaWBy0akvu8tCQKeQ+d7wsy5zLpz1FlzU3kW1QP+x40ApWgWAySEJTv6/NitNMkllcTakwCaZZ5ADEf6cROas/RhYVQps5igEpkZLwzRROmG04OjDBcj7+Js+vYQDo9e0uH1qzeY5/s1vtaaqG969+vTTrsmBTMLLv12nuy7l+d5W673SBzxkzlfhPdWSXokdZMkSFWhuUDzTTtOnk6CuG2fBEwI9etrHXOmRLJUE0/vMH14In5vH30sCS4Nkr+WmARdztHQ6Jr02dUFPtJ/lyxUVgq6/UzyO1olSj9jc+0DcaWxe/fqab/UT51Uu7Znjw6lbUn5QWtR6vtJQM//4zPUt+NOw+lGzCqo/gLm1QS8)
[Essayer en ligne](https://play.vuejs.org/#eNqNVNtq20AQ/ZWpQnECujhO0qaqY+hD25fQl4RCifKwllbKktXushcT1/W/d1bSSnYJNCCEZmbPmcuZ1S76olS6cTTKo6UpNVN2VQjWKqktfCOi3N4yY6HWsoVZmo0eD5kVAqAQ9KU7XNGaOG5h572lRAZBhTV574CJzJv7QuCzzMaMaFjaKk4sRQtgOeUmiiVO85siwncRQa6oThRpKHrO50XUnUdEwMMJw08M7mAtq20MzlAtSEtj4OyZGkweMIiq2AZKToxBgMcdxDCqVrueBfb7ZaaOQiOspZYgbL0FPBySIQD+eMeQc99/HJIsM0weqs+O258mjfZREE1jt5yCKaWiFXpSX0A/5loKmxj2m+YwT69p+7kXg0udw8nlYn19fYGufvSeZBXF0ZGmR2vwmrJKS4WiPswGWWYxzIIgs8fYH6mIJadnQXdNrdMiWAB+yJ7gsXdgLfjqcK10wtJqgmYZ+spnpGgl6up5oaa2fGKi6U8Yau9ZS6Wzpwi7WU1p7BMzaZcLbuBh0q2XM4fZXTc+uOPSGvjuWEWxlaAexr9uiIBf0qG3Uy6HxXwo9B+mn47CvbNSM+LHccDxAyvmjMA9Vdxh1WQiO0eywBVGEaN3Pj972wVxPKwOZ7BJWI2b+K5rOOVUNPbpYJNvJalwZmmahm3j7AhdSz3sPzDRS3R4SQwOCXxP4yVBzJqJarSzcY8H5mXWFfif1QVwPGjGcQWTLp7YrcLxCfyDdAuMW0cq30AOV+plcK1J+dxoXJkqR6igRCeNxjbxp3N6cX5V0Sb2K19dfFrA4uo9Gh8uP9K6Puvw3eyx9SH3IT/qPCZpiW6Y8Gq9mvekrutAN96o/V99ALPj)
### Composants sans affichage {#renderless-components}
Le cas d'utilisation `` dont nous avons parlé ci-dessus encapsule à la fois la logique réutilisable (récupération de données, pagination, etc.) et l'affichage, tout en déléguant une partie de l'affichage au composant consommateur via des scoped slots.
Si nous poussons ce concept un peu plus loin, nous pouvons proposer des composants qui encapsulent uniquement la logique et n'affichent rien par eux-mêmes - l'affichage est entièrement délégué au composant consommateur avec des scoped slots. Nous appelons ce type de composant un **Composant sans affichage** (Renderless Component).
Un exemple de composant sans affichage pourrait être un composant qui encapsule la logique de suivi de la position actuelle de la souris :
```vue-html
Mouse is at: {{ x }}, {{ y }}
```
[Essayer en ligne](https://play.vuejs.org/#eNqNUcFqhDAQ/ZUhF12w2rO4Cz301t5aaCEX0dki1SQko6uI/96J7i4qLPQQmHmZ9+Y9ZhQvxsRdiyIVmStsZQgcUmtOUlWN0ZbgXbcOP2xe/KKFs9UNBHGyBj09kCpLFj4zuSFsTJ0T+o6yjUb35GpNRylG6CMYYJKCpwAkzWNQOcgphZG/YZoiX/DQNAttFjMrS+6LRCT2rh6HGsHiOQKtmKIIS19+qmZpYLrmXIKxM1Vo5Yj9HD0vfD7ckGGF3LDWlOyHP/idYPQCfdzldTtjscl/8MuDww78lsqHVHdTYXjwCpdKlfoS52X52qGit8oRKrRhwHYdNrrDILouPbCNVZCtgJ1n/6Xx8JYAmT8epD3fr5cC0oGLQYpkd4zpD27R0vA=)
[Essayer en ligne](https://play.vuejs.org/#eNqVUU1rwzAM/SvCl7SQJTuHdLDDbttthw18MbW6hjW2seU0oeS/T0lounQfUDBGepaenvxO4tG5rIkoClGGra8cPUhT1c56ghcbA756tf1EDztva0iy/Ds4NCbSAEiD7diicafigeA0oFvLPAYNhWICYEE5IL00fMp8Hs0JYe0OinDIqFyIaO7CwdJGihO0KXTcLriK59NYBlUARTyMn6Hv0yHgIp7ARAvl3FXm8yCRiuu1Fv/x23JakVqtz3t5pOjNOQNoC7hPz0nHyRSzEr7Ghxppb/XlZ6JjRlzhTAlA+ypkLWwAM6c+8G2BdzP+/pPbRkOoL/KOldH2mCmtnxr247kKhAb9KuHKgLVtMEkn2knG+sIVzV9sfmy8hfB/swHKwV0oWja4lQKKjoNOivzKrf4L/JPqaQ==)
Bien qu'il s'agisse d'un pattern intéressant, la plupart de ce qui peut être réalisé avec les composants sans affichage peut être réalisé de manière plus efficace avec la Composition API, sans subir les coûts liés à l'imbrication de composants supplémentaires. Plus tard, nous verrons comment nous pouvons implémenter la même fonctionnalité de suivi de la souris mais avec un [Composable](/guide/reusability/composables).
Cela dit, les scoped slots sont toujours utiles dans les cas où nous devons à la fois encapsuler la logique **et** composer un affichage, comme dans l'exemple ``.
---
---
url: /api/sfc-spec.md
---
# Spécifications liées à la syntaxe des composants monofichiers {#sfc-syntax-specification}
## Vue d'ensemble {#overview}
Un composant monopage Vue, ou *Single-File Component* (SFC), utilisant conventionnellement l'extension de fichier `*.vue`, est un format de fichier personnalisé qui utilise une syntaxe de type HTML pour décrire un composant Vue. Un SFC Vue est syntaxiquement compatible avec le HTML.
Chaque fichier `*.vue` se compose de trois types de blocs de langage de haut niveau : ``, `
This could be e.g. documentation for the component.
```
## Blocs de langage {#language-blocks}
### `` {#template}
* Chaque fichier `*.vue` peut contenir au maximum un bloc de haut niveau `` à la fois.
* Le contenu sera extrait et transmis à `@vue/compiler-dom`, pré-compilé en fonctions de rendu JavaScript, et attaché au composant exporté en tant que son option `render`.
### `
```
`lang` peut être appliqué à n'importe quel bloc - par exemple, nous pouvons utiliser `
```
Notez que l'intégration avec divers pré-processeurs peut différer selon les outils utilisés. Consultez la documentation correspondante pour des exemples :
* [Vite](https://vite.dev/guide/features.html#css-pre-processors)
* [Vue CLI](https://cli.vuejs.org/guide/css.html#pre-processors)
* [webpack + vue-loader](https://vue-loader.vuejs.org/guide/pre-processors.html#using-pre-processors)
## Imports src {#src-imports}
Si vous préférez séparer vos composants `*.vue` en plusieurs fichiers, vous pouvez utiliser l'attribut `src` pour importer un fichier externe pour un bloc de langage :
```vue
```
Attention, les importations `src` suivent les mêmes règles de résolution de chemin que les requêtes de modules de webpack, ce qui signifie que :
* Les chemins relatifs doivent commencer par `./`.
* Vous pouvez importer des ressources à partir des dépendances npm :
```vue
```
Les importations `src` fonctionnent également avec des blocs personnalisés, par exemple :
```vue
```
:::warning Note
Lorsque vous utilisez des alias dans `src`, ne commencez pas par `~`, tout ce qui suit est interprété comme une requête de module. Cela signifie que vous pouvez référencer des assets à l'intérieur de node modules :
```vue
```
:::
## Commentaires {#comments}
À l'intérieur de chaque bloc, vous devez utiliser la syntaxe de commentaires du langage utilisé (HTML, CSS, JavaScript, Pug, etc.). Pour les commentaires de haut niveau, utilisez la syntaxe de commentaire HTML : ``
---
---
url: /guide/built-ins/suspense.md
---
# Suspense {#suspense}
:::warning Fonctionnalité expérimentale
`` est une fonctionnalité expérimentale. Il n'est pas garanti qu'elle atteigne un statut stable et l'API peut changer avant ce stade.
:::
`` est un composant natif pour orchestrer les dépendances asynchrones dans un arbre de composants. Il peut assurer le rendu d'un état de chargement en attendant que les multiples dépendances asynchrones imbriquées dans l'arbre de composants soient résolues.
## Dépendances asynchrones {#async-dependencies}
Pour expliquer le problème que `` essaie de résoudre et comment il interagit avec ces dépendances asynchrones, imaginons une hiérarchie de composants comme celle qui suit :
```
└─
├─
│ └─ (composant avec un setup() asynchrone)
└─
├─ (composant asynchrone)
└─ (composant asynchrone)
```
Dans l'arbre des composants, il y a plusieurs composants imbriqués dont le rendu dépend d'une ressource asynchrone qui doit d'abord être résolue. Sans ``, chacun d'entre eux devra gérer son propre chargement, ses erreurs, et ses états de chargement. Dans le pire des cas, nous pourrions voir trois roues de chargement sur la page, avec un contenu qui s'affiche à des moments différents.
Le composant `` nous donne la possibilité d'afficher des états de chargement/erreur de haut niveau pendant que nous attendons que ces dépendances asynchrones imbriquées soient résolues.
Il existe deux types de dépendances asynchrones pour lesquelles `` peut attendre :
1. Les composants avec un hook `setup()` asynchrone. Cela inclut les composants utilisant `
{{ posts }}
```
### Composants asynchrones {#async-components}
Les composants asynchrones sont, par défaut, **"suspensibles "**. Cela signifie que s'il a un `` dans la chaîne parentale, un composant asynchrone sera traité comme une dépendance asynchrone de ce ``. Dans ce cas, l'état de chargement sera contrôlé par le ``, et les options de chargement, d'erreur, de délai et de temporisation propres au composant seront ignorées.
Le composant asynchrone peut désactiver le contrôle de `Suspense` et laisser le composant contrôler son propre état de chargement en spécifiant `suspensible : false` dans ses options.
## État de chargement {#loading-state}
Le composant `` possède deux slots : `#default` et `#fallback`. Les deux slots n'acceptent qu'un seul nœud comme enfant direct. Le nœud dans le slot par défaut est affiché si cela est possible. Sinon, le nœud dans le slot de secours sera affiché.
```vue-html
Loading...
```
Lors du rendu initial, `` rendra le contenu de son slot par défaut en mémoire. Si des dépendances asynchrones sont rencontrées pendant le processus, il entrera dans un état d'**attente**. Pendant l'état d'attente, le contenu de secours sera affiché. Lorsque toutes les dépendances asynchrones rencontrées sont résolues, `` entre dans un état **résolu** et le contenu résolu du slot par défaut est affiché.
Si aucune dépendance asynchrone n'a été rencontrée lors du rendu initial, `` passera directement dans un état résolu.
Une fois dans un état résolu, `` ne reviendra à un état d'attente que si le nœud racine du slot `#default` est remplacé. Les nouvelles dépendances asynchrones imbriquées plus profondément dans l'arbre ne feront **pas** repasser le `` à l'état d'attente.
Lorsqu'il y a un retour en arrière, le contenu de secours ne sera pas immédiatement affiché. À la place, `` affichera le contenu `#default` précédent en attendant que le nouveau contenu et ses dépendances asynchrones soient résolus. Ce comportement peut être configuré avec la prop `timeout` : `` basculera vers un contenu de secours si le rendu du nouveau contenu par défaut prend plus de temps que la valeur de `timeout` en millisecondes. Une valeur de `timeout` de `0` fera que le contenu de secours sera affiché immédiatement lorsque le contenu par défaut sera remplacé.
## Événements {#events}
Le composant `` émet trois événements : `pending`, `resolve` et `fallback`. L'événement `pending` est émis lorsqu'on entre dans un état d'attente. L'événement `resolve` est émis lorsqu'un nouveau contenu a fini d'être résolu dans le slot `default`. L'événement `fallback` est émis lorsque le contenu du slot `fallback` est affiché.
Les événements peuvent être utilisés, par exemple, pour afficher un indicateur de chargement au niveau de l'ancien DOM pendant le chargement des nouveaux composants.
## Gestion des erreurs {#error-handling}
Il n'y a actuellement pas de gestion des erreurs fournie par `` lui même - cependant, vous pouvez utiliser l'option [`errorCaptured`](/api/options-lifecycle#errorcaptured) ou le hook [`onErrorCaptured()`](/api/composition-api-lifecycle#onerrorcaptured) pour intercepter et gérer les erreurs asynchrones dans le composant parent de ``.
## Combinaison avec d'autres composants {#combining-with-other-components}
Il est courant de vouloir utiliser `` en combinaison avec les composants [``](./transition) et [``](./keep-alive). L'ordre d'imbrication de ces composants est important pour qu'ils fonctionnent tous correctement.
De plus, ces composants sont souvent utilisés en association avec le composant `` de [Vue Router](https://router.vuejs.org/).
L'exemple suivant montre comment imbriquer ces composants afin qu'ils se comportent tous comme prévu. Pour des combinaisons plus simples, vous pouvez supprimer les composants dont vous n'avez pas besoin :
```vue-html
Loading...
```
Vue Router supporte nativement les [composants chargés de manière paresseuse](https://router.vuejs.org/guide/advanced/lazy-loading.html) via l'utilisation des importations dynamiques. Ceux-ci sont distincts des composants asynchrones et, actuellement, ils ne déclenchent pas ``. Cependant, ils peuvent toujours avoir des composants asynchrones comme descendants et ceux-ci peuvent déclencher `` normalement.
## Suspense imbriqué {#nested-suspense}
* Supporté à partir de la version 3.3
Lorsque nous avons plusieurs composants asynchrones (ce qui est courant pour les routes imbriquées ou basées sur la mise en page) comme ceci :
```vue-html
```
`` crée une frontière qui résoudra tous les composants asynchrones en bas de l'arbre, comme prévu. Cependant, lorsque nous modifions `DynamicAsyncOuter`, `` l'attend correctement, mais lorsque nous modifions `DynamicAsyncInner`, `DynamicAsyncInner` imbriqué rend un noeud vide jusqu'à ce qu'il soit résolu (au lieu du noeud précédent ou du slot de repli).
Pour résoudre ce problème, nous pourrions avoir un suspense imbriqué pour gérer le correctif pour le composant imbriqué, comme par exemple :
```vue-html
```
Si vous ne définissez pas la prop `suspensible`, le `` interne sera traité comme un composant sync par le parent ``. Cela signifie qu'il a son propre slot de repli et que si les deux composants `Dynamic` changent en même temps, il pourrait y avoir des noeuds vides et de multiples cycles de correction pendant que l'enfant `` charge son propre arbre de dépendance, ce qui n'est pas forcément souhaitable. Quand il est défini, toute la gestion asynchrone des dépendances est donnée au parent `` (y compris les événements émis) et le `` intérieur sert uniquement de frontière pour la résolution des dépendances et le patching.
***
**Référence**
* [Référence de l'API ``](/api/built-in-components#suspense)
---
---
url: /guide/essentials/template-syntax.md
---
# Syntaxe de template {#template-syntax}
Vue utilise une syntaxe de template basée sur HTML pour permettre de lier de manière déclarative le DOM rendu aux données de l'instance du composant sous-jacent. Tous les templates Vue sont du HTML syntaxiquement valide qui peut être analysé par des navigateurs et des analyseurs HTML conformes aux spécifications.
Sous le capot, Vue compile les templates en code JavaScript hautement optimisé. Combiné avec le système de réactivité, Vue est capable de déterminer intelligemment le nombre minimal de composants à restituer et d'appliquer la quantité minimale de manipulations DOM lorsque l'état de l'application change.
Si vous connaissez les concepts de DOM virtuel et préférez la puissance brute de JavaScript, vous pouvez également [écrire directement des fonctions de rendu](/guide/extras/render-function) au lieu des templates, avec en option la prise en charge de JSX. Cependant, notez qu'elles ne bénéficient pas du même niveau d'optimisation au moment de la compilation que les templates.
## Interpolation de texte {#text-interpolation}
La forme la plus élémentaire de liaison de données est l'interpolation de texte à l'aide de la syntaxe "Moustache" (doubles accolades) :
```vue-html
Message : {{ msg }}
```
La balise moustache sera remplacée par la valeur de la propriété `msg` de [l'instance du composant correspondant](/guide/essentials/reactivity-fundamentals#declaring-reactive-state). Elle sera également mise à jour chaque fois que la propriété `msg` changera.
## HTML brut {#raw-html}
Les doubles moustaches interprètent les données comme du texte brut et non comme du HTML. Afin de produire du vrai HTML, vous devrez utiliser la directive [`v-html`](/api/built-in-directives#v-html) :
```vue-html
Using text interpolation: {{ rawHtml }}
Using v-html directive:
```
Ici, nous rencontrons quelque chose de nouveau. L'attribut `v-html` que vous voyez s'appelle une **directive**. Les directives sont préfixées par `v-` pour indiquer qu'il s'agit d'attributs spéciaux fournis par Vue et, comme vous l'avez peut-être deviné, elles appliquent un comportement réactif spécial au DOM rendu. Ici, nous disons essentiellement "maintenir à jour le code HTML interne de cet élément avec la propriété `rawHtml` sur l'instance active actuelle".
Le contenu de `span` sera remplacé par la valeur de la propriété `rawHtml`, interprétée comme du HTML simple - les liaisons de données sont ignorées. Notez que vous ne pouvez pas utiliser `v-html` pour composer des templates partiels, car Vue n'est pas un moteur de template basé sur des chaînes de caractères. Au lieu de cela, les composants sont préférés comme unité fondamentale pour la réutilisation et la composition de l'interface utilisateur.
:::warning Avertissement de sécurité
L'affichage dynamique de code HTML arbitraire sur votre site Web peut être très dangereux, car il peut facilement entraîner des [vulnérabilités XSS](https://en.wikipedia.org/wiki/Cross-site_scripting). N'utilisez `v-html` que sur le contenu de confiance et **jamais** sur le contenu fourni par l'utilisateur.
:::
## Liaisons d'attributs {#attribute-bindings}
Les moustaches ne peuvent pas être utilisées dans les attributs HTML. À la place, utilisez une directive [`v-bind`](/api/built-in-directives#v-bind) :
```vue-html
```
La directive `v-bind` demande à Vue de garder l'attribut `id` de l'élément synchronisé avec la propriété `dynamicId` du composant. Si la valeur liée est `null` ou `undefined`, alors l'attribut sera supprimé de l'élément rendu.
### Raccourci {#shorthand}
Parce que `v-bind` est si couramment utilisée, elle a une syntaxe raccourcie :
```vue-html
```
Les attributs commençant par `:` peuvent sembler un peu différents du HTML normal, mais il s'agit en fait d'un caractère valide pour les noms d'attributs et tous les navigateurs pris en charge par Vue peuvent l'analyser correctement. De plus, ils n'apparaissent pas dans le rendu final. La syntaxe abrégée est facultative, mais vous l'apprécierez probablement lorsque vous en apprendrez plus sur son utilisation plus tard.
> Pour le reste du guide, nous utiliserons la syntaxe abrégée dans les exemples de code, car c'est l'utilisation la plus courante pour les développeurs Vue.
### Raccourci de même nom {#same-name-shorthand}
* Supporté à partir de la version 3.4
Si l'attribut porte le même nom que le nom de la variable de la valeur JavaScript à lier, la syntaxe peut encore être raccourcie pour omettre la valeur de l'attribut :
```vue-html
```
C'est similaire au raccourci pour déclarer un objet en JavaScript. Notez que cette fonctionnalité n'est disponible que pour les versions 3.4 et suivantes de Vue.
### Attributs booléens {#boolean-attributes}
[Les attributs booléens](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes) sont des attributs qui peuvent indiquer des valeurs vrai/faux par leur présence sur un élément. Par exemple, [`disabled`](https://developer.mozilla.org/fr/docs/Web/HTML/Attributes/disabled) est l'un des attributs booléens les plus couramment utilisés.
`v-bind` fonctionne un peu différemment dans ce cas :
```vue-html
Button
```
L'attribut `disabled` sera inclus si `isButtonDisabled` a une [valeur évaluée à vrai](https://developer.mozilla.org/fr/docs/Glossary/Truthy). Il sera également inclus si la valeur est une chaîne vide, en maintenant la cohérence avec ``. Pour les [valeurs évaluées à faux](https://developer.mozilla.org/fr/docs/Glossary/Falsy), l'attribut sera omis.
### Liaison dynamique de plusieurs attributs {#dynamically-binding-multiple-attributes}
Si vous avez un objet JavaScript représentant plusieurs attributs qui ressemble à ceci :
```js
const objectOfAttrs = {
id: 'container',
class: 'wrapper',
style: 'background-color:green'
}
```
```js
data() {
return {
objectOfAttrs: {
id: 'container',
class: 'wrapper'
}
}
}
```
Vous pouvez les lier à un seul élément en utilisant `v-bind` sans argument :
```vue-html
```
## Utilisation d'expressions JavaScript {#using-javascript-expressions}
Jusqu'à présent, nous n'avons lié que des clés de propriété simples dans nos templates. Mais Vue prend en charge toute la puissance des expressions JavaScript dans toutes les liaisons de données :
```html
{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{
message.split('').reverse().join('') }}
```
Ces expressions seront évaluées comme du JavaScript dans la portée des données de l'instance de composant actuelle.
Dans les templates Vue, les expressions JavaScript peuvent être utilisées dans les positions suivantes :
* Dans une interpolation de texte (moustaches)
* Dans la valeur d'attribut de toutes les directives Vue (attributs spéciaux qui commencent par `v-`)
### Expressions uniquement {#expressions-only}
Chaque liaison ne peut contenir qu'**une seule expression**. Une expression est un morceau de code qui peut donner une valeur. Une simple vérification est de savoir si elle peut être utilisée après un `return`.
Par conséquent, ce qui suit ne fonctionnera **PAS** :
```html
{{ var a = 1 }}
{{ if (ok) { return message } }}
```
### Appel de fonctions {#calling-functions}
Il est possible d'appeler une méthode exposée au composant dans une expression de liaison :
```html
{{ formatDate(date) }}
```
:::tip
Les fonctions appelées à l'intérieur des expressions de liaison seront appelées à chaque mise à jour du composant, elles ne doivent donc **pas** avoir d'effets de bord, tels que la modification de données ou le déclenchement d'opérations asynchrones.
:::
### Accès global restreint {#restricted-globals-access}
Les expressions de template sont en bac à sable et n'ont accès qu'à une [liste restreinte de variables globales](https://github.com/vuejs/core/blob/main/packages/shared/src/globalsAllowList.ts#L3). La liste expose les variables globales intégrées couramment utilisées telles que `Math` et `Date`.
Les variables globales non explicitement incluses dans la liste, par exemple les propriétés jointes par l'utilisateur sur `window`, ne seront pas accessibles dans les expressions du template. Vous pouvez cependant définir explicitement des variables globales supplémentaires pour toutes les expressions Vue en les ajoutant à [`app.config.globalProperties`](/api/application#app-config-globalproperties).
## Directives {#directives}
Les directives sont des attributs spéciaux avec pour préfixe `v-`. Vue propose un certain nombre de [directives natives](/api/built-in-directives), dont `v-html` et `v-bind` que nous venons d'introduire précédemment.
Les valeurs attendues dans les directives sont une seule expression JavaScript (à l'exception de `v-for`, `v-on` et `v-slot`, que l'on présentera dans leur section respective). Le travail d'une directive est d'appliquer les changements au DOM en réaction aux changements de la valeur de son expression. Prenez [`v-if`](/api/built-in-directives#v-if) comme exemple :
```vue-html
Now you see me
```
Ici, la directive `v-if` va supprimer ou insérer l'élément `` selon la valeur booléenne de l'expression `seen`.
### Arguments {#arguments}
Certaines directives peuvent prendre un "argument", distingué par un double-point après le nom de la directive. Par exemple, la directive `v-bind` est utilisée pour mettre à jour par réaction un attribut HTML :
```vue-html
...
...
```
Ici `href` est l'argument, qui suggère à la directive `v-bind` de lier l'attribut `href` de l'élément à l'expression `url`. Par un raccourci, tout ce qui se trouve avant l'argument (pour `v-bind:`) est condensé au simple caractère `:`.
Autre exemple avec la directive `v-on`, qui écoute les événements du DOM :
```vue-html
...
...
```
Ici l'argument est le nom de l'événement à écouter : `click`. `v-on` a un raccourci dédié, le caractère `@`. Nous en parlerons également en détail sur la gestion de événements.
### Arguments dynamiques {#dynamic-arguments}
Il est également possible d'utiliser une expression JavaScript dans l'argument d'une directive en l'entourant de crochets :
```vue-html
...
...
```
Ici `attributeName` sera dynamiquement évalué comme une expression JavaScript, et sa valeur évaluée sera utilisée comme valeur finale pour l'argument. Par exemple, si l'instance du composant a une propriété, `attributeName`, et que sa valeur est `"href"`, alors la liaison sera équivalent à `v-bind:href`.
De manière similaire, vous pouvez utiliser des arguments dynamiques pour lier un gestionnaire à un nom d'événement dynamique :
```vue-html
...
...
```
Dans cet exemple, quand la valeur de `eventName` est `"focus"`, `v-on:[eventName]` sera équivalent à `v-on:focus`.
#### Contraintes de valeur des arguments dynamiques {#dynamic-argument-value-constraints}
Les arguments dynamiques sont prévus pour être évalués en une chaîne de caractères, avec `null` pour exception. La valeur spéciale `null` peut être utilisée pour supprimer explicitement la liaison. Toute autre valeur non-chaînée déclenchera un avertissement.
#### Contraintes de syntaxe des arguments dynamiques {#dynamic-argument-syntax-constraints}
Les expressions d'argument dynamique ont quelques contraintes syntaxique à cause de certains caractères, comme les espaces et les guillemets, qui sont invalides pour des noms d'attributs HTML :
```vue-html
...
```
Si vous devez passer un argument dynamique complexe, il est probablement préférable d'utiliser une [propriété calculée](./computed), que nous aborderons sous peu.
Lorsque vous utilisez des templates dans le DOM (templates directement écrits dans un fichier HTML), vous devez également éviter de nommer les clés avec des caractères majuscules, car les navigateurs contraindront les noms d'attributs en minuscules :
```vue-html
...
```
Ci-dessus sera converti en `:[someattr]` dans les templates dans le DOM. Si votre composant a une propriété `someAttr` au lieu de `someattr`, votre code ne fonctionnera pas. Les templates à l'intérieur des composants à fichier unique **ne sont pas** soumis à cette contrainte.
### Modificateurs {#modifiers}
Les modificateurs sont des suffixes spéciaux désignés par un point, qui indiquent qu'une directive doit être liée d'une manière spéciale. Par exemple, le modificateur `.prevent` indique à la directive `v-on` d'appeler `event.preventDefault()` sur l'événement déclenché :
```vue-html
```
Vous verrez d'autres exemples de modificateurs plus tard, [pour `v-on`](./event-handling#event-modifiers) et [pour `v-model`](./forms#modifiers), lorsque nous explorerons ces fonctionnalités.
Et enfin, voici la syntaxe complète de la directive visualisée :

---
---
url: /guide/extras/animation.md
---
# Techniques d'animation {#animation-techniques}
Vue fournit les composants [``](/guide/built-ins/transition) et [``](/guide/built-ins/transition-group) pour gérer les transitions d'entrée / sortie et de liste. Cependant, il existe de nombreuses autres manières d'utiliser des animations sur le web, même dans une application Vue. Ici, nous allons discuter de quelques techniques supplémentaires.
## Animations basées sur des classes {#class-based-animations}
Pour les éléments qui n'entrent pas / ne quittent pas le DOM, nous pouvons déclencher des animations en ajoutant dynamiquement une classe CSS :
```js
const disabled = ref(false)
function warnDisabled() {
disabled.value = true
setTimeout(() => {
disabled.value = false
}, 1500)
}
```
```js
export default {
data() {
return {
disabled: false
}
},
methods: {
warnDisabled() {
this.disabled = true
setTimeout(() => {
this.disabled = false
}, 1500)
}
}
}
```
```vue-html
Click me
This feature is disabled!
```
```css
.shake {
animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
transform: translate3d(0, 0, 0);
}
@keyframes shake {
10%,
90% {
transform: translate3d(-1px, 0, 0);
}
20%,
80% {
transform: translate3d(2px, 0, 0);
}
30%,
50%,
70% {
transform: translate3d(-4px, 0, 0);
}
40%,
60% {
transform: translate3d(4px, 0, 0);
}
}
```
## Animations pilotées par l'état {#state-driven-animations}
Certaines transitions peuvent être appliquées en interpolant des valeurs, par exemple en liant un style à un élément pendant qu'une interaction se produit. Prenons cet exemple :
```js
const x = ref(0)
function onMousemove(e) {
x.value = e.clientX
}
```
```js
export default {
data() {
return {
x: 0
}
},
methods: {
onMousemove(e) {
this.x = e.clientX
}
}
}
```
```vue-html
Move your mouse across this div...
x: {{ x }}
```
```css
.movearea {
transition: 0.3s background-color ease;
}
```
En plus de la couleur, vous pouvez également utiliser des liaisons de style pour animer la transformation, la largeur ou la hauteur. Vous pouvez même animer des chemins SVG en utilisant la physique de ressort - après tout, ce sont toutes des liaisons de données d'attributs :
## Animer avec des observateurs {#animating-with-watchers}
Avec un peu de créativité, nous pouvons utiliser des observateurs pour animer n'importe quoi en fonction d'un état numérique. Par exemple, nous pouvons animer le nombre lui-même :
```js
import { ref, reactive, watch } from 'vue'
import gsap from 'gsap'
const number = ref(0)
const tweened = reactive({
number: 0
})
// Note: Pour les entrées plus supérieures que Number.MAX_SAFE_INTEGER (9007199254740991),
// le résultat peut être incohérent en raison des limitations sur la précision des nombres en JavaScript.
watch(number, (n) => {
gsap.to(tweened, { duration: 0.5, number: Number(n) || 0 })
})
```
```vue-html
Type a number:
{{ tweened.number.toFixed(0) }}
```
```js
import gsap from 'gsap'
export default {
data() {
return {
number: 0,
tweened: 0
}
},
// Note: Pour les entrées plus supérieures que Number.MAX_SAFE_INTEGER (9007199254740991),
// le résultat peut être incohérent en raison des limitations sur la précision des nombres en JavaScript.
watch: {
number(n) {
gsap.to(this, { duration: 0.5, tweened: Number(n) || 0 })
}
}
}
```
```vue-html
Type a number:
{{ tweened.toFixed(0) }}
```
[Essayer en ligne](https://play.vuejs.org/#eNpNUstygzAM/BWNLyEzBDKd6YWSdHrpsacefSGgJG7xY7BImhL+vTKv9ILllXYlr+jEm3PJpUWRidyXjXIEHql1e2mUdrYh6KDBY8yfoiR1wRiuBZVn6OHYWA0r5q6W2pMv3ISHkBPSlNZ4AtPqAzawC2LRdj3DdEU0WA34qB910sBUnsFWmp6LpRmaRo9UHMLIrGG3h4EBQ/OEbDRpxjx51TYFKWtYKHmOF9WP4Qzs+x22EDoA9NLwmaejC/x+vhBqVxeEfAPIK3WBsi6830lRobZSDDjA580hFIt8roxrCS4bbSuskxFmzhhIAenEy92id1CnzZzfd91szETmZ72rH6zYOej7PA3rYXrKE3GUp//m5KunWx3C5CE6enS0hjZXVKczZXCwdfWyoF79YgZPqBliJ9iGSUTEYlzuRrO9X94a/lUGNTklvBTZvAMpwhYCIMWZyPksTVvjvk9JaXUacq9sSlujFJPnvej/AElH3FQ=)
[Essayer en ligne](https://play.vuejs.org/#eNpNUctugzAQ/JWVLyESj6hSL5Sm6qXHnnr0xYENuAXbwus8Svj3GlxIJEvendHMvgb2bkx6cshyVtiyl4b2XMnO6J6gtsLAsdcdbKZwwxVXeJmpCo/CtQQDVwCVIBFtQwzQI7leLRmAct0B+xx28YLQGVFh5aGAjNM3zvRZUNnkizhII7V6w9xTSjqiRtoYBqhcL0hq5c3S5/hu/blKbzfYwbh9LMWVf0W2zusTws60gnDK6OtqEMTaeSGVcQSnpNMVtmmAXzkLAWeQzarCQNkKaz1zkHWysPthWNryjX/IC1bRbgvjWGTG64rssbQqLF3bKUzvHmH6o1aUnFHWDeVw0G31sqJW/mIOT9h5KEw2m7CYhUsmnV/at9XKX3n24v+E5WxdNmfTbieAs4bI2DzLnDI/dVrqLpu4Nz+/a5GzZYls/AM3dcFx)
---
---
url: /guide/built-ins/teleport.md
---
# Teleport {#teleport}
`` est un composant natif qui nous permet de "téléporter" une partie du template d'un composant dans un nœud du DOM qui existe en dehors de la hiérarchie du DOM de ce composant.
## Utilisation basique {#basic-usage}
Parfois, nous pouvons être confrontés au scénario suivant : une partie du template d'un composant lui appartient logiquement, mais d'un point de vue visuel, elle devrait être affichée ailleurs dans le DOM, peut-être même en dehors de l'application Vue.
L'exemple le plus courant est la création d'une modale plein écran. Idéalement, nous souhaitons que le code du bouton de la modale et la modale elle-même soient écrits dans le même composant à fichier unique, puisqu'ils sont tous les deux liés à l'état d'ouverture / fermeture de la modale. Mais cela signifie que la modale sera rendue à côté du bouton, profondément imbriquée dans la hiérarchie du DOM de l'application. Cela peut causer des problèmes délicats lors du positionnement de la modale via CSS.
Considérez la structure HTML suivante.
```vue-html
```
Et voici une implémentation de ``:
```vue
Open Modal
Hello from the modal!
Close
```
```vue
Open Modal
Hello from the modal!
Close
```
Le composant comporte un `` pour déclencher l'ouverture de la modale, ainsi qu'une `` avec une classe `.modal`, qui va contenir le contenu de la modale et un bouton pour se fermer.
Lorsque nous utilisons ce composant à l'intérieur de la structure HTML initiale, il y a un certain nombre de problèmes potentiels :
* `position : fixed` ne place l'élément relativement à la fenêtre d'affichage que si aucun élément ancêtre n'a la propriété `transform`, `perspective` ou `filter` définie. Si, par exemple, nous voulons animer l'ancêtre `
` avec une transformation CSS, cela casserait la disposition de la modale !
* Le `z-index` de la modale est restreint par les éléments dans lesquels elle est imbriquée. S'il y a un autre élément qui chevauche `
` et a un `z-index` plus élevé, il couvrira notre modale.
`
` fournit une manière propre de résoudre ces problèmes, en nous permettant de sortir de la structure imbriquée du DOM. Modifions `` pour utiliser `` :
```vue-html{3,8}
Open Modal
Hello from the modal!
Close
```
La cible `to` de `` attend une chaîne de sélecteur CSS ou un nœud du DOM actif. Ici, nous disons essentiellement à Vue de "**téléporter** ce fragment de template **vers** la balise **`body`**".
Vous pouvez cliquer sur le bouton ci-dessous et inspecter la balise `body` via la console de votre navigateur :
Vous pouvez combiner `` avec [``](./transition) pour créer des modales animées - voir l'[exemple ici](/examples/#modal).
:::tip
La cible de téléportation `to` doit déjà figurer dans le DOM au moment où le composant `` est monté. Idéalement, il devrait s'agir d'un élément situé en dehors de l'application Vue. Si vous ciblez un autre élément rendu par Vue, vous devez vous assurer que cet élément est monté avant le ``. Si vous utilisez le SSR, consultez [Gestion des téléportations en SSR](/guide/scaling-up/ssr#teleports).
:::
## Utilisation avec les composants {#using-with-components}
`` ne modifie que la structure DOM rendue - il n'affecte pas la hiérarchie logique des composants. En d'autres termes, si `` contient un composant, ce composant restera un enfant logique du composant parent contenant le ``. Le passage des props et l'émission d'événements continueront de fonctionner de la même manière.
Cela signifie également que les injections à partir d'un composant parent fonctionnent comme prévu, et que le composant enfant sera imbriqué sous le composant parent dans les Devtools Vue, au lieu d'être placé là où le contenu réel a été déplacé.
## Désactiver Teleport {#disabling-teleport}
Dans certains cas, nous pouvons vouloir désactiver `` de manière conditionnelle. Par exemple, nous pouvons vouloir rendre un composant en overlay sur les périphériques desktop, mais inline sur la version mobile. `` prend en charge l'option `disabled` qui peut être activée dynamiquement :
```vue-html
...
```
Nous pourrions alors mettre à jour dynamiquement `isMobile`.
## Plusieurs Teleports sur la même cible {#multiple-teleports-on-the-same-target}
Un cas d'utilisation courant serait un composant `` réutilisable, avec la possibilité que plusieurs instances soient actives en même temps. Pour ce type de scénario, plusieurs composants `` peuvent monter leur contenu sur le même élément cible. L'ordre sera le même qu'avec un simple ajout avec les derniers montages seront situés après les précédents, mais tous à l'intérieur de l'élément cible.
Étant donné l'utilisation suivante :
```vue-html
A
B
```
Le résultat rendu serait :
```html
```
## Deferred Teleport {#deferred-teleport}
In Vue 3.5 and above, we can use the `defer` prop to defer the target resolving of a Teleport until other parts of the application have mounted. This allows the Teleport to target a container element that is rendered by Vue, but in a later part of the component tree:
```vue-html
...
```
Note that the target element must be rendered in the same mount / update tick with the Teleport - i.e. if the `` is only mounted a second later, the Teleport will still report an error. The defer works similarly to the `mounted` lifecycle hook.
***
**Référence**
* [Référence de l'API `
`](/api/built-in-components#teleport)
* [Gérer les Teleports en SSR](/guide/scaling-up/ssr#teleports)
---
---
url: /guide/scaling-up/testing.md
---
# Tester {#testing}
## Pourquoi tester ? {#why-test}
Les tests automatisés vous aident ainsi que votre équipe à construire des applications Vue complexes rapidement et avec confiance en prévenant les régressions et en vous encourageant à décomposer votre application en fonctions, modules, classes et composants testables. Comme toute autre application, votre nouvelle application Vue peut dysfonctionner de différentes manières, et il est important que vous puissiez détecter ces problèmes avant de livrer.
Dans ce guide, nous allons couvrir la terminologie basique et donner des recommandations d'outils à choisir pour votre application Vue 3.
Une section dédiée à Vue couvre les composables. Voir [Tester les composables](#testing-composables) ci-dessous pour plus de détails.
## Quand tester ? {#when-to-test}
Commencez tôt ! Nous recommandons de commencer à écrire des tests dès que vous le pouvez. Plus vous attendrez avant d'ajouter des tests à votre application, plus votre application aura des dépendances, et il sera plus difficile de commencer.
## Types de tests {#testing-types}
Quand vous concevez la stratégie de test de votre application Vue, vous devriez mettre en place les types de tests suivants :
* **Unitaire** : Vérifie que les entrées d'une fonction, classe, ou composable donné produisent les sorties ou effets de bord attendus.
* **Composant** : Vérifie que le montage, le rendu, les interactions et le comportement d'un composant ont lieu comme prévu. Ces tests exercent plus de code que des tests unitaires, sont plus complexes et requièrent plus de temps pour s'exécuter.
* **End-to-end** : Vérifie des fonctionnalités qui traversent plusieurs pages et émettent des vraies requêtes réseau sur votre application Vue construite pour la production. Ces tests impliquent souvent la mise en place d'une base de données ou d'un autre backend.
Chaque type de test joue un rôle dans la stratégie de test de votre application, et vous protégera de différents problèmes.
## Aperçu {#overview}
Nous allons brièvement discuter de ce que chacun de ces tests sont, de comment ils peuvent être implémentés pour des applications Vue et donner quelques recommendations générales.
## Tester unitairement {#unit-testing}
Les tests unitaires sont écrits pour vérifier que des petites unités de code isolées fonctionnent comme prévu. Un test unitaire couvre généralement une seule fonction, classe, composable ou module. Les tests unitaires se concentrent sur l'exactitude logique et ne concernent qu'une petite partie des fonctionnalités globales de l'application. Ils peuvent simuler de grandes parties de l'environnement de votre application (par exemple, l'état initial, les classes complexes, les modules tierce partie et les requêtes réseau).
En général, les tests unitaires vont détecter des problèmes concernant la logique métier d'une fonction et son exactitude logique.
Prenons par exemple cette fonction `increment` :
```js [helpers.js]
export function increment(current, max = 10) {
if (current < max) {
return current + 1
}
return current
}
```
Comme cette fonction est très autonome, il sera facile de l'appeler et de vérifier qu'elle retourne ce qu'elle est supposée faire, nous allons donc écrire un test unitaire.
Si l'une de ces assertions échoue, il est clair que le problème est contenu dans la fonction `increment`.
```js{3-15} [helpers.spec.js]
import { increment } from './helpers'
describe('increment', () => {
test('increments the current number by 1', () => {
expect(increment(0, 10)).toBe(1)
})
test('does not increment the current number over the max', () => {
expect(increment(10, 10)).toBe(10)
})
test('has a default max of 10', () => {
expect(increment(10)).toBe(10)
})
})
```
Comme mentionné précédemment, les tests unitaires sont généralement exercés sur de la logique métier, des composants, classes, modules, ou fonctions qui ne nécessitent pas de rendu visuel, de requêtes réseau, ou d'autres problématiques d'environnement.
Il s'agit généralement de modules écrits en JavaScript / TypeScript simple sans rapport avec Vue. En général, écrire des tests unitaires pour de la logique métier dans des applications Vue ne diffère pas de manière significative des applications utilisant d'autres frameworks.
Il existe deux cas où vous testez unitairement des fonctionnalités spécifiques à Vue :
1. Composables
2. Composants
### Composables {#composables}
[Les composables](/guide/reusability/composables) sont une catégorie de fonctions spécifiques aux applications Vue qui peut nécessiter un traitement spécial pendant les tests.
Voir la section [Tester les composables](#testing-composables) ci-dessous pour plus de détails.
### Tester unitairement des composants {#unit-testing-components}
Un composant peut être testé de deux façons :
1. Boîte blanche : Test unitaire
Les tests "Boîte blanche" ont "conscience" des détails d'implémentation et des dépendances d'un composant. Ils se concentrent sur l'**isolation** du composant testé. Ces tests impliquent en général de simuler certains sinon tous les enfants de votre composant ainsi que d'initialiser l'état de plugins et dépendances (ex. Pinia).
2. Boîte noire : Test de composant
Les tests "Boîte noire" n'ont pas "conscience" des détails d'implémentation d'un composant. Ces tests simulent le moins possible afin de tester l'intégration de vos composants et le système entier. Ils font généralement le rendu HTML de l'ensemble des sous-composants et sont considérés plus comme un "test d'intégration". Voir les [recommendations de test de composant](#component-testing) ci-dessous.
### Recommandation {#recommendation-1}
* [Vitest](https://vitest.dev/)
Étant donné que la configuration officielle créée par `create-vue` est basée sur [Vite](https://vite.dev/), nous vous recommandons d'utiliser un framework de test unitaire pour tirer parti de la même configuration et pipeline de transformation directement à partir de Vite. [Vitest](https://vitest.dev/) est un framework de test unitaire conçu spécifiquement à cet effet, créé et maintenu par les membres de l'équipe Vue / Vite. Il s'intègre aux projets basés sur Vite avec un minimum d'effort et est ultrarapide.
### Autres options {#other-options}
* [Jest](https://jestjs.io/) est un framework de test unitaire populaire. Cependant, nous ne recommandons Jest que si vous avez une suite de tests Jest existante qui doit être migrée vers un projet basé sur Vite, car Vitest offre une intégration plus transparente et de meilleures performances.
## Test de composant {#component-testing}
Dans les applications Vue, les composants sont les principaux blocs de construction de l'interface utilisateur. Les composants sont donc l'unité naturelle d'isolement lorsqu'il s'agit de valider le comportement de votre application. Du point de vue de la granularité, les tests de composants se situent quelque part au-dessus des tests unitaires et peuvent être considérés comme une forme de test d'intégration. Une grande partie de votre application Vue doit être couverte par un test de composant et nous vous recommandons que chaque composant Vue ait son propre fichier de spécifications.
Les tests de composant doivent détecter les problèmes liés aux props, aux événements, aux slots qu'un composant fournit, aux styles, aux classes, aux hooks de cycle de vie de votre composant, etc.
Les tests de composant ne doivent pas simuler des composants enfants, mais plutôt tester les interactions entre votre composant et ses enfants en interagissant avec les composants comme le ferait un utilisateur. Par exemple, un test de composant doit cliquer sur un élément comme le ferait un utilisateur au lieu d'interagir programmatiquement avec le composant.
Les tests de composant doivent se concentrer sur les interfaces publiques du composant plutôt que sur les détails internes d'implémentation. Pour la plupart des composants, l'interface publique est limitée aux événements émis, aux props et aux slots. Lors du test, n'oubliez pas de **tester ce que fait un composant, pas comment il le fait**.
**FAITES**
* Pour la logique **visuelle** : vérifiez que le rendu en sortie est correct en fonction des props et des slots saisis.
* Pour la logique **comportementale** : vérifiez que les mises à jour de rendu ou les événements émis en réponse aux événements d'entrée de l'utilisateur sont corrects.
Dans l'exemple ci-dessous, nous démontrons un composant Stepper qui a un élément DOM intitulé "increment" et sur lequel vous pouvez cliquer. Nous passons une prop appelée `max` qui empêche le Stepper d'être incrémenté au-delà de `2`, donc si nous cliquons sur le bouton 3 fois, l'interface utilisateur devrait toujours dire `2`.
Nous ne savons rien de l'implémentation de Stepper, seulement que l'"entrée" est la prop `max` et que la "sortie" est l'état du DOM tel que l'utilisateur le verra.
::: code-group
```js [Vue Test Utils]
const valueSelector = '[data-testid=stepper-value]'
const buttonSelector = '[data-testid=increment]'
const wrapper = mount(Stepper, {
props: {
max: 1
}
})
expect(wrapper.find(valueSelector).text()).toContain('0')
await wrapper.find(buttonSelector).trigger('click')
expect(wrapper.find(valueSelector).text()).toContain('1')
```
```js [Cypress]
const valueSelector = '[data-testid=stepper-value]'
const buttonSelector = '[data-testid=increment]'
mount(Stepper, {
props: {
max: 1
}
})
cy.get(valueSelector)
.should('be.visible')
.and('contain.text', '0')
.get(buttonSelector)
.click()
.get(valueSelector)
.should('contain.text', '1')
```
```js [Testing Library]
const { getByText } = render(Stepper, {
props: {
max: 1
}
})
getByText('0') // Vérification implicite que "0" se trouve dans le composant
const button = getByRole('button', { name: /increment/i })
// Envoi d'un événement click sur notre bouton d'incrémentation.
await fireEvent.click(button)
getByText('1')
await fireEvent.click(button)
```
:::
**NE FAITES PAS**
* Ne vérifiez pas l'état privé d'une instance de composant et ne testez pas les méthodes privées d'un composant. Tester les détails de l'implémentation rend les tests fragiles, car ils sont plus susceptibles de se rompre et nécessitent des mises à jour lorsque l'implémentation change.
Le travail ultime du composant est un rendu DOM en sortie correct, de sorte que les tests axés sur la sortie DOM fournissent le même niveau d'assurance d'exactitude (sinon plus) tout en étant plus robustes et résilients au changement.
Ne vous fiez pas exclusivement aux tests snapshots. Vérifier des chaînes HTML ne décrit pas l'exactitude. Rédigez des tests avec intention.
Si une méthode doit être testée de manière approfondie, envisagez de l'extraire dans une fonction utilitaire autonome et d'écrire un test unitaire dédié à celle-ci. S'il ne peut pas être extrait proprement, il peut être testé dans le cadre d'un test de composant, d'intégration ou bout-en-bout qui le couvre.
### Recommendation {#recommandation}
* [Vitest](https://vitest.dev/) pour les composants ou composables qui ont un rendu headless (ex. la fonction [`useFavicon`](https://vueuse.org/core/useFavicon/#usefavicon) dans VueUse). Les composants et le DOM peuvent être testés à l'aide de [`@vue/test-utils`](https://github.com/vuejs/test-utils).
* [Les tests de composants Cypress](https://on.cypress.io/component) pour les composants dont le comportement attendu dépend du rendu correct des styles ou du déclenchement d'événements DOM natifs. Peut être utilisé avec Testing Library via [`@testing-library/cypress`](https://testing-library.com/docs/cypress-testing-library/intro).
Les principales différences entre Vitest et les runners basés sur un navigateur sont la rapidité et le contexte d'exécution. En bref, les runners basés sur un navigateur, comme Cypress, peuvent détecter des problèmes que les runners basés sur node, comme Vitest, ne peuvent pas détecter (par exemple, les problèmes de style, les événements DOM natifs réels, les cookies, le local storage et les défaillances réseau), mais les runners basés sur un navigateur sont *bien plus lents que Vitest* parce qu'ils ouvrent un navigateur, compilent vos feuilles de style, etc. Cypress est un runner basé sur un navigateur qui prend en charge les tests de composants. Veuillez lire [la page de comparaison de Vitest](https://vitest.dev/guide/comparisons.html#cypress) pour obtenir les dernières informations comparant Vitest et Cypress.
### Bibliothèques de montage {#mounting-libraries}
Le test de composant implique souvent le montage du composant testé isolément, le déclenchement d'événements d'entrée utilisateur simulés et la vérification du rendu DOM en sortie. Il existe des bibliothèques d'utilitaires dédiées qui simplifient ces tâches.
* [`@vue/test-utils`](https://github.com/vuejs/test-utils) est la bibliothèque officielle de test de composants de bas niveau qui a été écrite pour permettre aux utilisateurs d'accéder à des API spécifiques à Vue. C'est aussi la bibliothèque de bas niveau sur laquelle `@testing-library/vue` est construite.
* [`@testing-library/vue`](https://github.com/testing-library/vue-testing-library) est une bibliothèque de test Vue axée sur le test de composants sans s'appuyer sur les détails de l'implémentation. Construit avec l'accessibilité à l'esprit, son approche rend également la refactorisation un jeu d'enfant. Son principe directeur est que plus les tests ressemblent à la façon dont les logiciels sont utilisés, plus on peut leur faire confiance.
Nous vous recommandons d'utiliser `@vue/test-utils` pour tester les composants dans les applications. `@testing-library/vue` a des problèmes avec le test du composant asynchrone avec Suspense, il doit donc être utilisé avec prudence.
* [Nightwatch](https://nightwatchjs.org/) est un testeur E2E avec prise en charge de Vue Component Testing. ([Projet d'exemple](https://github.com/nightwatchjs-community/todo-vue))
* [WebdriverIO](https://webdriver.io/docs/component-testing/vue) pour les tests de composants inter-navigateurs qui reposent sur une interaction utilisateur native basée sur une automatisation standardisée. Peut également être utilisé avec la bibliothèque de tests.
## Tests E2E {#e2e-testing}
Alors que les tests unitaires offrent aux développeurs un certain degré de confiance, les tests unitaires et les tests de composants sont limités dans leur capacité à fournir une couverture holistique d'une application lorsqu'ils sont déployés en production. En conséquence, les tests End-to-end (E2E) offrent une couverture sur ce qui est sans doute l'aspect le plus important d'une application : ce qui se passe lorsque les utilisateurs utilisent réellement vos applications.
Les tests End-to-end se concentrent sur le comportement des applications multipages qui effectuent des requêtes réseau par rapport à votre application Vue de production. Ils impliquent souvent la mise en place d'une base de données ou d'un autre backend et peuvent même être exécutés dans un environnement de staging déployé.
Les tests End-to-end détectent souvent des problèmes avec votre routeur, votre bibliothèque de gestion d'état, vos composants de niveau supérieur (par exemple, une application ou une mise en page), vos ressources publiques ou toute autre gestion de requêtes. Comme indiqué ci-dessus, ils détectent des problèmes critiques qui peuvent être impossibles à détecter avec des tests unitaires ou des tests de composants.
Les tests End-to-end n'importent pas le code de votre application Vue, mais reposent entièrement sur le test de votre application en naviguant dans des pages entières dans un navigateur réel.
Les tests End-to-end valident de nombreuses couches de votre application. Ils peuvent soit cibler votre application localement soit même un environnement de staging déployé. Les tests exercés sur votre environnement de staging incluent non seulement votre code frontend et votre serveur statique mais également tous les services et infrastructures backend associés.
> Plus vos tests ressemblent à la manière dont votre application est utilisée, plus ils vous donneront confiance. [Kent C. Dodds](https://x.com/kentcdodds/status/977018512689455106), auteur de la bibliothèque de tests
En testant l'impact des actions des utilisateurs sur votre application, les tests E2E sont souvent la clé d'une plus grande confiance dans le bon fonctionnement ou non d'une application.
### Choisir une solution de test E2E {#choosing-an-e2e-testing-solution}
Alors que les tests End-to-end (E2E) sur le Web ont acquis une réputation négative pour les tests peu fiables ("flaky") et le ralentissement des processus de développement, les outils E2E modernes ont fait des progrès pour créer des tests plus fiables, interactifs et utiles. Lorsque vous choisissez une infrastructure de test E2E, les sections suivantes fournissent des conseils sur les éléments à garder à l'esprit lors du choix d'une infrastructure de test pour votre application.
#### Tester avec plusieurs navigateurs {#cross-browser-testing}
L'un des principaux avantages pour lesquels les tests End-to-end (E2E) sont connus est sa capacité à tester votre application sur plusieurs navigateurs. Bien qu'il puisse sembler souhaitable d'avoir une couverture inter-navigateurs à 100%, il est important de noter que les tests inter-navigateurs ont des rendements décroissants sur les ressources d'une équipe en raison du temps supplémentaire et de la puissance de la machine nécessaire pour les exécuter de manière cohérente. Par conséquent, il est important d'être conscient de ce compromis lorsque vous choisissez la quantité de tests inter-navigateurs dont votre application a besoin.
#### Des boucles de feedback plus rapides {#faster-feedback-loops}
L'un des principaux problèmes liés aux tests et au développement End-to-end (E2E) est que l'exécution de l'ensemble de la suite prend beaucoup de temps. En règle générale, cela n'est fait que dans les pipelines d'intégration et de déploiement continus (CI/CD). Les frameworks de test E2E modernes ont aidé à résoudre ce problème en ajoutant des fonctionnalités telles que la parallélisation, ce qui permet aux pipelines CI / CD d'exécuter souvent des magnitudes plus rapidement qu'auparavant. En outre, lors du développement local, la possibilité d'exécuter de manière sélective un seul test pour la page sur laquelle vous travaillez tout en fournissant un rechargement à chaud des tests peut aider à améliorer le flux de travail et la productivité d'un développeur.
#### First-class debugging experience {#first-class-debugging-experience}
Alors que les développeurs s'appuyaient traditionnellement sur l'analyse des logs dans une fenêtre de terminal pour aider à déterminer ce qui n'allait pas dans un test, les frameworks de test modernes End-to-end (E2E) permettent aux développeurs de tirer parti d'outils qu'ils connaissent déjà, par exemple les outils de développement de navigateur.
#### Visibilité en mode headless {#visibility-in-headless-mode}
Lorsque les tests End-to-end (E2E) sont exécutés dans des pipelines d'intégration/déploiement continus, ils sont souvent exécutés dans des navigateurs headless (c'est-à-dire qu'aucun navigateur visible n'est ouvert pour que l'utilisateur puisse le regarder). Une caractéristique essentielle des frameworks de test E2E modernes est la possibilité de voir des snapshots et / ou des vidéos de l'application pendant les tests, fournissant un aperçu des raisons pour lesquelles des erreurs se produisent. Historiquement, il était fastidieux de maintenir ces intégrations.
### Recommandation {#recommentation-2}
* [Playwright](https://playwright.dev/) est une excellente solution de test E2E qui prend en charge Chromium, WebKit et Firefox. Testez sur Windows, Linux et macOS, localement ou sur CI, headless ou non avec l'émulation mobile native de Google Chrome pour Android et Mobile Safari. Il dispose d'une interface utilisateur informative, d'une excellente débogabilité, d'assertions intégrées, d'une parallélisation, de traces et est conçu pour éliminer les tests défectueux. La prise en charge des [tests de composants](https://playwright.dev/docs/test-components) est disponible, mais est considérée comme expérimentale. Playwright est open source et maintenu par Microsoft.
* [Cypress](https://www.cypress.io/) dispose d'une interface graphique informative, une excellente déboguabilité, des assertions et des stubs intégrés, une résistance à la "flakiness" des tests, une parallélisation et des instantanés. Comme mentionné ci-dessus, il offre également un support pour [les tests de composants](https://docs.cypress.io/guides/component-testing/introduction). Il prend en charge les navigateurs basés sur Chromium, Firefox et Electron. Le support de WebKit est disponible, mais marqué comme expérimental. Cypress est sous licence MIT, mais certaines fonctionnalités comme la parallélisation nécessitent un abonnement à Cypress Cloud.
### Autres options {#other-options-2}
* [Nightwatch](https://nightwatchjs.org/) est une solution de test E2E basée sur [Selenium WebDriver](https://www.npmjs.com/package/selenium-webdriver). Cela lui permet de prendre en charge le plus grand nombre de navigateurs, y compris les tests mobiles natifs. Les solutions basées sur Selenium seront plus lentes que Playwright ou Cypress.
* [WebdriverIO](https://webdriver.io/) est un framework d'automatisation des tests pour les tests Web et mobiles basé sur le protocole WebDriver.
## Recettes {#recipes}
### Ajouter Vitest a un projet {#adding-vitest-to-a-project}
Dans un projet Vue basé sur Vite, lancez :
```sh
> npm install -D vitest happy-dom @testing-library/vue
```
Ensuite, modifiez la configuration Vite pour ajouter le bloc d'option `test` :
```js{6-12} [vite.config.js]
import { defineConfig } from 'vite'
export default defineConfig({
// ...
test: {
// active les API compatibles avec jest globalement
globals: true,
// simule le DOM avec happy-dom
// (requiert l'installation de happy-dom en dépendance additionnelle)
environment: 'happy-dom'
}
})
```
:::tip
Si vous utilisez TypeScript, ajoutez, add `vitest/globals` dans le champ `types` de votre `tsconfig.json`.
```json [tsconfig.json]
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
```
:::
Créez ensuite un fichier se terminant par `*.test.js` dans votre projet. Vous pouvez placer tous les fichiers de test dans un répertoire de test à la racine du projet ou dans des répertoires de test à côté de vos fichiers sources. Vitest les recherchera automatiquement à l'aide de la convention de nommage.
```js [MyComponent.test.js]
import { render } from '@testing-library/vue'
import MyComponent from './MyComponent.vue'
test('it should work', () => {
const { getByText } = render(MyComponent, {
props: {
/* ... */
}
})
// assert output
getByText('...')
})
```
Enfin, mettez à jour `package.json` pour ajouter le script de test et lancez-le :
```json{4} [package.json]
{
// ...
"scripts": {
"test": "vitest"
}
}
```
```sh
> npm test
```
### Tester les Composables {#testing-composables}
> Cette section suppose que vous avez lu la section [Composables](/guide/reusability/composables).
Lorsqu'il est question de tester des composables, nous pouvons diviser en deux catégories : les composables qui ne dépendent pas d'une instance de composant hôte et ceux qui en dépendent.
Un composable dépend d'une instance de composant hôte quand il utilise une des API suivantes :
* Hooks du cycle de vie
* Provide / Inject
Si un composable utilise uniquement les API de réactivité, alors il peut être testé directement en l'invoquant et en vérifiant l'état et les méthodes qu'il retourne :
```js [counter.js]
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
const increment = () => count.value++
return {
count,
increment
}
}
```
```js [counter.test.js]
import { useCounter } from './counter.js'
test('useCounter', () => {
const { count, increment } = useCounter()
expect(count.value).toBe(0)
increment()
expect(count.value).toBe(1)
})
```
Un composable qui s'appuie sur des hooks de cycle de vie ou Provide / Inject doit être contenu dans un composant enveloppe pour être testé. Nous pouvons créer une fonction utilitaire comme ci-dessous :
```js [test-utils.js]
import { createApp } from 'vue'
export function withSetup(composable) {
let result
const app = createApp({
setup() {
result = composable()
// supprime l'avertissement du template manquant
return () => {}
}
})
app.mount(document.createElement('div'))
// renvoie le résultat et l'instance de l'application
// pour les tests, provide/unmount
return [result, app]
}
```
```js [foo.test.js]
import { withSetup } from './test-utils'
import { useFoo } from './foo'
test('useFoo', () => {
const [result, app] = withSetup(() => useFoo(123))
// simule provide pour tester les injections
app.provide(...)
// exécute les assertions
expect(result.foo.value).toBe(1)
// déclenche le hook onUnmounted si nécessaire
app.unmount()
})
```
Il peut également être plus facile de tester des composables plus complexes en écrivant des tests contre le composant enveloppe en utilisant les techniques de [Test de Composant](#component-testing).
---
---
url: /translations.md
---
# Traductions {#translations}
## Langues disponibles {#available-languages}
* [English](https://vuejs.org/) \[[source](https://github.com/vuejs/docs)]
* [简体中文 / Simplified Chinese](https://cn.vuejs.org/) \[[source](https://github.com/vuejs-translations/docs-zh-cn)]
* [日本語 / Japanese](https://ja.vuejs.org/) \[[source](https://github.com/vuejs-translations/docs-ja)]
* [Українська / Ukrainian](https://ua.vuejs.org) \[[source](https://github.com/vuejs-translations/docs-ua)]
* [Français / French](https://fr.vuejs.org) \[[source](https://github.com/vuejs-translations/docs-fr)]
* [한국어 / Korean](https://ko.vuejs.org) \[[source](https://github.com/vuejs-translations/docs-ko)]
* [Português / Portuguese](https://pt.vuejs.org) \[[source](https://github.com/vuejs-translations/docs-pt)]
* [বাংলা / Bengali](https://bn.vuejs.org) \[[source](https://github.com/vuejs-translations/docs-bn)]
* [Italiano / Italian](https://it.vuejs.org) \[[source](https://github.com/vuejs-translations/docs-it)]
* [فارسی / Persian](https://fa.vuejs.org) \[[source](https://github.com/vuejs-translations/docs-fa)]
* [Русский / Russian](https://ru.vuejs.org/) \[[source](https://github.com/vuejs-translations/docs-ru)]
* [Čeština / Czech](https://cs.vuejs.org/) \[[source](https://github.com/vuejs-translations/docs-cs)]
* [繁體中文 / Traditional Chinese](https://zh-hk.vuejs.org/) \[[source](https://github.com/vuejs-translations/docs-zh-hk)]
* [Polski / Polonais](https://pl.vuejs.org/) \[[source](https://github.com/vuejs-translations/docs-pl)]
## Work in Progress Languages {#work-in-progress-languages}
* [العربية / Arabic](https://ar.vuejs.org/) \[[source](https://github.com/vuejs-translations/docs-ar)]
* [Español / Spanish](https://vue3-spanish-docs.netlify.app/) \[[source](https://github.com/icarusgk/vuejs-spanish-docs)]
* [Deutsch / Allemand](https://de.vuejs.org/) \[[source](https://github.com/vuejs-translations/docs-de)]
## Commencer une nouvelle traduction {#starting-a-new-translation}
La documentation de Vue a récemment subi une révision majeure, ainsi les traductions dans d'autres langues sont toujours manquantes ou en cours de développement.
Nous saluons les efforts de la communauté pour fournir plus de traductions. Les efforts de traduction sont gérés dans l'organisation GitHub [vuejs-translations](https://github.com/vuejs-translations/). Si vous souhaitez contribuer, veuillez consulter les [Directives de traduction](https://github.com/vuejs-translations/guidelines/blob/main/README.md) pour commencer.
---
---
url: /guide/built-ins/transition.md
---
# Transition {#transition}
Vue propose deux composants natifs qui peuvent aider à travailler avec des transitions et des animations en réponse à un changement d'état :
* ``pour appliquer des animations lorsqu'un élément ou un composant entre et sort du DOM. Ceci est couvert sur cette page.
* `` pour appliquer des animations lorsqu'un élément ou un composant est inséré, supprimé ou déplacé dans une liste `v-for`. Ceci est couvert dans [le chapitre suivant](/guide/built-ins/transition-group).
Outre ces deux composants, nous pouvons également appliquer des animations dans Vue en utilisant d'autres techniques telles que le basculement des classes CSS ou des animations basées sur l'état via des liaisons de style. Ces techniques supplémentaires sont traitées dans le chapitre [Techniques d'animation](/guide/extras/animation).
## Le composant `` {#the-transition-component}
`` est un composant intégré : cela signifie qu'il est disponible dans n'importe quel template de composant sans avoir à l'enregistrer. Il peut être utilisé pour appliquer des animations d'entrée et de sortie sur des éléments ou des composants qui lui sont transmis via son slot par défaut. L'entrée ou la sortie peut être déclenchée par l'une des actions suivantes :
* Rendu conditionnel via `v-if`
* Affichage conditionnel via `v-show`
* Basculement des composants dynamiques via l'élément spécial ``
* Changer l'attribut spécial `key`
Voici un exemple de l'utilisation la plus basique :
```vue-html
Toggle
hello
```
```css
/* nous vous expliquerons ensuite ce que font ces classes ! */
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
```
[Essayer en ligne](https://play.vuejs.org/#eNpVkEFuwyAQRa8yZZNWqu1sunFJ1N4hSzYUjRNUDAjGVJHluxcCipIV/OG/pxEr+/a+TwuykfGogvYEEWnxR2H17F0gWCHgBBtMwc2wy9WdsMIqZ2OuXtwfHErhlcKCb8LyoVoynwPh7I0kzAmA/yxEzsKXMlr9HgRr9Es5BTue3PlskA+1VpFTkDZq0i3niYfU6anRmbqgMY4PZeH8OjwBfHhYIMdIV1OuferQEoZOKtIJ328TgzJhm8BabHR3jeC8VJqusO8/IqCM+CnsVqR3V/mfRxO5amnkCPuK5B+6rcG2fydshks=)
[Essayer en ligne](https://play.vuejs.org/#eNpVkMFuAiEQhl9lyqlNuouXXrZo2nfwuBeKs0qKQGBAjfHdZZfVrAmB+f/M/2WGK/v1vs0JWcdEVEF72vQWz94Fgh0OMhmCa28BdpLk+0etAQJSCvahAOLBnTqgkLA6t/EpVzmCP7lFEB69kYRFAYi/ROQs/Cij1f+6ZyMG1vA2vj3bbN1+b1Dw2lYj2yBt1KRnXRwPudHDnC6pAxrjBPe1n78EBF8MUGSkixnLNjdoCUMjFemMn5NjUGacnboqPVkdOC+Vpgus2q8IKCN+T+suWENwxyWJXKXMyQ5WNVJ+aBqD3e6VSYoi)
:::tip
`` ne prend en charge qu'un seul élément ou composant comme contenu du slot. Si le contenu est un composant, le composant doit également avoir un seul élément racine.
:::
Lorsqu'un élément d'un composant `` est inséré ou supprimé, voici ce qui se passe :
1. Vue détectera automatiquement si l'élément cible a des transitions CSS ou des animations appliquées. Si c'est le cas, un certain nombre de [classes de transition CSS](#transition-classes) seront ajoutées / supprimées aux moments appropriés.
2. S'il existe des écouteurs pour les [hooks JavaScript](#javascript-hooks), ces hooks seront appelés aux moments appropriés.
3. Si aucune transition / animation CSS n'est détectée et qu'aucun hook JavaScript n'est fourni, les opérations DOM d'insertion et / ou de suppression seront exécutées lors du prochain rafraîchissement d'animation du navigateur.
## Transitions basées sur le CSS {#css-based-transitions}
### Classes de transition {#transition-classes}
Six classes sont appliquées pour les transitions entrée / sortie.

1. `v-enter-from` : état de départ pour l'entrée. Ajoutée avant l'insertion de l'élément, supprimée une frame après l'insertion de l'élément.
2. `v-enter-active` : état actif pour l'entrée. Appliquée pendant toute la phase d'entrée. Ajoutée avant l'insertion de l'élément, supprimée à la fin de la transition / animation. Cette classe peut être utilisée pour définir la durée, le retard et la courbe d'accélération de la transition entrante.
3. `v-enter-to` : état de fin pour l'entrée. Ajoutée une frame après l'insertion de l'élément (en même temps `v-enter-from` est supprimée), supprimée lorsque la transition / animation se termine.
4. `v-leave-from` : état de départ pour la sortie. Ajoutée immédiatement lorsqu'une transition de sortie est déclenchée, supprimée après une frame.
5. `v-leave-active` : état actif pour la sortie. Appliquée pendant toute la phase de sortie. Ajoutée immédiatement lorsqu'une transition de sortie est déclenchée, supprimée lorsque la transition/animation se termine. Cette classe peut être utilisée pour définir la durée, le retard et la courbe d'accélération de la transition de sortie.
6. `v-leave-to` : état de fin pour la sortie. Ajoutée une frame après le déclenchement d'une transition de sortie (en même temps `v-leave-from` est supprimée), supprimée lorsque la transition/animation se termine.
`v-enter-active` et `v-leave-active` nous donnent la possibilité de spécifier différentes courbes d'accélération pour les transitions entrée/sortie, dont nous verrons un exemple dans les sections suivantes.
### Transitions nommées {#named-transitions}
Une transition peut être nommée via la prop `name` :
```vue-html
...
```
Pour une transition nommée, ses classes de transition seront préfixées par son nom au lieu de `v`. Par exemple, la classe appliquée pour la transition ci-dessus sera `fade-enter-active` au lieu de `v-enter-active`. Le CSS pour la transition de fondu devrait ressembler à ceci :
```css
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
```
### Transitions CSS {#css-transitions}
`` est le plus souvent utilisé en combinaison avec [les transitions CSS natives](https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions), comme on le voit dans l'exemple basique ci-dessus. La propriété CSS `transition` est un raccourci qui nous permet de spécifier plusieurs aspects d'une transition, y compris les propriétés qui doivent être animées, la durée de la transition et les [courbes d'accélération](https://developer.mozilla.org/fr/docs/Web/CSS/easing-function).
Voici un exemple plus avancé qui effectue la transition de plusieurs propriétés, avec différentes durées et courbes d'accélération pour l'entrée et la sortie :
```vue-html
hello
```
```css
/*
Les animations d'entrée et de sortie peuvent utiliser différentes
durées et fonctions de temporisation.
*/
.slide-fade-enter-active {
transition: all 0.3s ease-out;
}
.slide-fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
```
[Essayer en ligne](https://play.vuejs.org/#eNqFkc9uwjAMxl/F6wXQKIVNk1AX0HbZC4zDDr2E4EK0NIkStxtDvPviFQ0OSFzyx/m+n+34kL16P+lazMpMRBW0J4hIrV9WVjfeBYIDBKzhCHVwDQySdFDZyipnY5Lu3BcsWDCk0OKosqLoKcmfLoSNN5KQbyTWLZGz8KKMVp+LKju573ivsuXKbbcG4d3oDcI9vMkNiqL3JD+AWAVpoyadGFY2yATW5nVSJj9rkspDl+v6hE/hHRrjRMEdpdfiDEkBUVxWaEWkveHj5AzO0RKGXCrSHcKBIfSPKEEaA9PJYwSUEXPX0nNlj8y6RBiUHd5AzCOodq1VvsYfjWE4G6fgEy/zMcxG17B9ZTyX8bV85C5y1S40ZX/kdj+GD1P/zVQA56XStC9h2idJI/z7huz4CxoVvE4=)
[Essayer en ligne](https://play.vuejs.org/#eNqFkc1uwjAMgF/F6wk0SmHTJNQFtF32AuOwQy+hdSFamkSJ08EQ776EbMAkJKTIf7I/O/Y+ezVm3HvMyoy52gpDi0rh1mhL0GDLvSTYVwqg4cQHw2QDWCRv1Z8H4Db6qwSyHlPkEFUQ4bHixA0OYWckJ4wesZUn0gpeainqz3mVRQzM4S7qKlss9XotEd6laBDu4Y03yIpUE+oB2NJy5QSJwFC8w0iIuXkbMkN9moUZ6HPR/uJDeINSalaYxCjOkBBgxeWEijnayWiOz+AcFaHNeU2ix7QCOiFK4FLCZPzoALnDXHt6Pq7hP0Ii7/EGYuag9itR5yv8FmgH01EIPkUxG8F0eA2bJmut7kbX+pG+6NVq28WTBTN+92PwMDHbSAXQhteCdiVMUpNwwuMassMP8kfAJQ==)
### Animations CSS {#css-animations}
[Les animations CSS natives](https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Animations/Using_CSS_animations) sont appliquées de la même manière que les transitions CSS, à la différence que `*-enter-from` n'est pas supprimée immédiatement après l'insertion de l'élément, mais lors d'un événement `animationend`.
Pour la plupart des animations CSS, nous pouvons simplement les déclarer sous les classes `*-enter-active` et `*-leave-active`. Voici un exemple :
```vue-html
Hello here is some bouncy text!
```
```css
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
}
```
[Essayer en ligne](https://play.vuejs.org/#eNqNksGOgjAQhl9lJNmoBwRNvCAa97YP4JFLbQZsLG3TDqzG+O47BaOezCYkpfB9/0wHbsm3c4u+w6RIyiC9cgQBqXO7yqjWWU9wA4813KH2toUpo9PKVEZaExg92V/YRmBGvsN5ZcpsTGGfN4St04Iw7qg8dkTWwF5qJc/bKnnYk7hWye5gm0ZjmY0YKwDlwQsTFCnWjGiRpaPtjETG43smHPSpqh9pVQKBrjpyrfCNMilZV8Aqd5cNEF4oFVo1pgCJhtBvnjEAP6i1hRN6BBUg2BZhKHUdvMmjWhYHE9dXY/ygzN4PasqhB75djM2mQ7FUSFI9wi0GCJ6uiHYxVsFUGcgX67CpzP0lahQ9/k/kj9CjDzgG7M94rT1PLLxhQ0D+Na4AFI9QW98WEKTQOMvnLAOwDrD+wC0Xq/Ubusw/sU+QL/45hskk9z8Bddbn)
[Essayer en ligne](https://play.vuejs.org/#eNqNUs2OwiAQfpWxySZ66I8mXioa97YP4LEXrNNKpEBg2tUY330pqOvJmBBgyPczP1yTb2OyocekTJirrTC0qRSejbYEB2x4LwmulQI4cOLTWbwDWKTeqkcE4I76twSyPcaX23j4zS+WP3V9QNgZyQnHiNi+J9IKtrUU9WldJaMMrGEynlWy2em2lcjyCPMUALazXDlBwtMU79CT9rpXNXp4tGYGhlQ0d7UqAUcXOeI6bluhUtKmhEVhzisgPFPKpWhVCTUqQrt6ygD8oJQajmgRhAOnO4RgdQm8yd0tNzGv/D8x/8Dy10IVCzn4axaTTYNZymsSA8YuciU6PrLL6IKpUFBkS7cKXXwQJfIBPyP6IQ1oHUaB7QkvjfUdcy+wIFB8PeZIYwmNtl0JruYSp8XMk+/TXL7BzbPF8gU6L95hn8D4OUJnktsfM1vavg==)
### Classes de transition personnalisées {#custom-transition-classes}
Vous pouvez également spécifier des classes de transition personnalisées en transmettant les props suivantes à `` :
* `enter-from-class`
* `enter-active-class`
* `enter-to-class`
* `leave-from-class`
* `leave-active-class`
* `leave-to-class`
Celles-ci remplaceront les noms de classes conventionnels. Ceci est particulièrement utile lorsque vous souhaitez combiner le système de transition de Vue avec une bibliothèque d'animation CSS existante, telle que [Animate.css](https://daneden.github.io/animate.css/) :
```vue-html
hello
```
[Essayer en ligne](https://play.vuejs.org/#eNqNUctuwjAQ/BXXF9oDsZB6ogbRL6hUcbSEjLMhpn7JXtNWiH/vhqS0R3zxPmbWM+szf02pOVXgSy6LyTYhK4A1rVWwPsWM7MwydOzCuhw9mxF0poIKJoZC0D5+stUAeMRc4UkFKcYpxKcEwSenEYYM5b4ixsA2xlnzsVJ8Yj8Mt+LrbTwcHEgxwojCmNxmHYpFG2kaoxO0B2KaWjD6uXG6FCiKj00ICHmuDdoTjD2CavJBCna7KWjZrYK61b9cB5pI93P3sQYDbxXf7aHHccpVMolO7DS33WSQjPXgXJRi2Cl1xZ8nKkjxf0dBFvx2Q7iZtq94j5jKUgjThmNpjIu17ZzO0JjohT7qL+HsvohJWWNKEc/NolncKt6Goar4y/V7rg/wyw9zrLOy)
[Essayer en ligne](https://play.vuejs.org/#eNqNUcFuwjAM/RUvp+1Ao0k7sYDYF0yaOFZCJjU0LE2ixGFMiH9f2gDbcVKU2M9+tl98Fm8hNMdMYi5U0tEEXraOTsFHho52mC3DuXUAHTI+PlUbIBLn6G4eQOr91xw4ZqrIZXzKVY6S97rFYRqCRabRY7XNzN7BSlujPxetGMvAAh7GtxXLtd/vLSlZ0woFQK0jumTY+FJt7ORwoMLUObEfZtpiSpRaUYPkmOIMNZsj1VhJRWeGMsFmczU6uCOMHd64lrCQ/s/d+uw0vWf+MPuea5Vp5DJ0gOPM7K4Ci7CerPVKhipJ/moqgJJ//8ipxN92NFdmmLbSip45pLmUunOH1Gjrc7ezGKnRfpB4wJO0ZpvkdbJGpyRfmufm+Y4Mxo1oK16n9UwNxOUHwaK3iQ==)
### Utiliser les transitions et les animations ensemble {#using-transitions-and-animations-together}
Vue doit attacher des écouteurs d'événements afin de savoir quand une transition est terminée. Cela peut être `transitionend` ou `animationend`, selon le type de règles CSS appliquées. Si vous n'utilisez que l'un ou l'autre, Vue peut automatiquement détecter le bon type.
Cependant, dans certains cas, vous voudrez peut-être avoir les deux sur le même élément, par exemple avoir une animation CSS déclenchée par Vue, ainsi qu'un effet de transition CSS au survol. Dans ces cas, vous devrez déclarer explicitement le type dont vous voulez que Vue se soucie en passant la prop `type`, avec une valeur de `animation` ou `transition` :
```vue-html
...
```
### Transitions imbriquées et durées de transition explicites {#nested-transitions-and-explicit-transition-durations}
Bien que les classes de transition ne soient appliquées qu'à l'élément enfant direct dans ``, nous pouvons effectuer la transition d'éléments imbriqués à l'aide de sélecteurs CSS imbriqués :
```vue-html
```
```css
/* règles qui ciblent les éléments imbriqués */
.nested-enter-active .inner,
.nested-leave-active .inner {
transition: all 0.3s ease-in-out;
}
.nested-enter-from .inner,
.nested-leave-to .inner {
transform: translateX(30px);
opacity: 0;
}
/* ... autre CSS nécessaire omis */
```
Nous pouvons même ajouter un délai de transition à l'élément imbriqué lors de l'entrée, ce qui crée une séquence d'animation d'entrée décalée :
```css{3}
/* retarde l'entrée de l'élément imbriqué pour un effet décalé */
.nested-enter-active .inner {
transition-delay: 0.25s;
}
```
Cependant, cela crée un petit problème. Par défaut, le composant `` tente de déterminer automatiquement quand la transition est terminée en écoutant le **premier** événement `transitionend` ou `animationend` sur l'élément de transition racine. Avec une transition imbriquée, le comportement souhaité doit attendre que les transitions de tous les éléments internes soient terminées.
Dans de tels cas, vous pouvez spécifier une durée de transition explicite (en millisecondes) à l'aide de la prop `duration` sur le composant ``. La durée totale doit correspondre au délai plus la durée de transition de l'élément interne :
```vue-html
...
```
[Essayer en ligne](https://play.vuejs.org/#eNqVVd9v0zAQ/leO8LAfrE3HNKSFbgKmSYMHQNAHkPLiOtfEm2NHttN2mvq/c7bTNi1jgFop9t13d9995ziPyfumGc5bTLJkbLkRjQOLrm2uciXqRhsHj2BwBiuYGV3DAUEPcpUrrpUlaKUXcOkBh860eJSrcRqzUDxtHNaNZA5pBzCets5pBe+4FPz+Mk+66Bf+mSdXE12WEsdphMWQiWHKCicoLCtaw/yKIs/PR3kCitVIG4XWYUEJfATFFGIO84GYdRUIyCWzlra6dWg2wA66dgqlts7c+d8tSqk34JTQ6xqb9TjdUiTDOO21TFvrHqRfDkPpExiGKvBITjdl/L40ulVFBi8R8a3P17CiEKrM4GzULIOlFmpQoSgrl8HpKFpX3kFZu2y0BNhJxznvwaJCA1TEYcC4E3MkKp1VIptjZ43E3KajDJiUMBqeWUBmcUBUqJGYOT2GAiV7gJAA9Iy4GyoBKLH2z+N0W3q/CMC2yCCkyajM63Mbc+9z9mfvZD+b071MM23qLC69+j8PvX5HQUDdMC6cL7BOTtQXCJwpas/qHhWIBdYtWGgtDWNttWTmThu701pf1W6+v1Hd8Xbz+k+VQxmv8i7Fv1HZn+g/iv2nRkjzbd6npf/Rkz49DifQ3dLZBBYOJzC4rqgCwsUbmLYlCAUVU4XsCd1NrCeRHcYXb1IJC/RX2hEYCwJTvHYVMZoavbBI09FmU+LiFSzIh0AIXy1mqZiFKaKCmVhiEVJ7GftHZTganUZ56EYLL3FykjhL195MlMM7qxXdmEGDPOG6boRE86UJVPMki+p4H01WLz4Fm78hSdBo5xXy+yfsd3bpbXny1SA1M8c82fgcMyW66L75/hmXtN44a120ktDPOL+h1bL1HCPsA42DaPdwge3HcO/TOCb2ZumQJtA15Yl65Crg84S+BdfPtL6lezY8C3GkZ7L6Bc1zNR0=)
Si nécessaire, vous pouvez également spécifier des valeurs distinctes pour les durées d'entrée et de sortie à l'aide d'un objet :
```vue-html
...
```
### Considérations relatives aux performances {#performance-considerations}
Vous remarquerez peut-être que les animations présentées ci-dessus utilisent principalement des propriétés telles que "transform" et "opacity". Ces propriétés sont efficaces pour animer car :
1. Elles n'affectent pas la mise en page du document pendant l'animation, elles ne déclenchent donc pas de calculs de mise en page CSS coûteux sur chaque image d'animation.
2. La plupart des navigateurs modernes peuvent tirer parti de l'accélération matérielle GPU lors de l'animation de `transform`.
En comparaison, des propriétés telles que `height` ou `margin` déclencheront la mise en page CSS, elles sont donc beaucoup plus coûteuses à animer et doivent être utilisées avec prudence.
## Hooks JavaScript {#javascript-hooks}
Vous pouvez vous connecter au processus de transition avec JavaScript en écoutant les événements sur le composant `` :
```vue-html
```
```js
// appelée avant que l'élément ne soit inséré dans le DOM.
// utilisez ceci pour définir l'état "enter-from" de l'élément.
function onBeforeEnter(el) {}
// appelée une frame après l'insertion de l'élément.
// utilisez ceci pour démarrer l'animation d'entrée.
function onEnter(el, done) {
// appelle la fonction de rappel done pour indiquer la fin de la transition
// facultative si utilisée en combinaison avec CSS
done()
}
// appelée lorsque la transition enter est terminée.
function onAfterEnter(el) {}
// appelée lorsque la transition enter est annulée avant la fin.
function onEnterCancelled(el) {}
// appelée avant le hook de sortie.
// la plupart du temps, vous devez simplement utiliser le hook de sortie.
function onBeforeLeave(el) {}
// appelée lorsque la transition de sortie démarre.
// utilisez ceci pour démarrer l'animation de sortie.
function onLeave(el, done) {
// appelle la fonction de rappel done pour indiquer la fin de la transition
// facultative si utilisée en combinaison avec CSS
done()
}
// appelée lorsque la transition de sortie est terminée et que
// l'élément a été supprimé du DOM.
function onAfterLeave(el) {}
// uniquement disponible avec les transitions v-show
function onLeaveCancelled(el) {}
```
```js
export default {
// ...
methods: {
// appelée avant que l'élément ne soit inséré dans le DOM.
// utilisez ceci pour définir l'état "enter-from" de l'élément
onBeforeEnter(el) {},
// appelée une frame après l'insertion de l'élément.
// utilisez ceci pour démarrer l'animation d'entrée.
onEnter(el, done) {
// appelle la fonction de rappel done pour indiquer la fin de la transition.
// facultative si utilisée en combinaison avec CSS
done()
},
// appelée lorsque la transition enter est terminée.
onAfterEnter(el) {},
// appelée lorsque la transition d'entrée est annulée avant d'être achevée.
onEnterCancelled(el) {},
// appelée avant le hook de sortie.
// la plupart du temps, vous devez simplement utiliser le hook de sortie.
onBeforeLeave(el) {},
// appelée lorsque la transition de sortie démarre.
// utilisez ceci pour démarrer l'animation de sortie.
onLeave(el, done) {
// appelle la fonction de rappel done pour indiquer la fin de la transition
// facultative si utilisée en combinaison avec CSS
done()
},
// appelée lorsque la transition de sortie est terminée et que
// l'élément a été supprimé du DOM.
onAfterLeave(el) {},
// uniquement disponible avec les transitions v-show
onLeaveCancelled(el) {}
}
}
```
Ces hooks peuvent être utilisés en combinaison avec des transitions / animations CSS ou seuls.
Lors de l'utilisation de transitions JavaScript uniquement, il est généralement judicieux d'ajouter la prop `:css="false"`. Cela indique explicitement à Vue d'ignorer la détection automatique des transitions CSS. En plus d'être légèrement plus performant, cela empêche également les règles CSS d'interférer accidentellement avec la transition :
```vue-html{3}
...
```
Avec `:css="false"`, nous sommes également entièrement responsables du contrôle de la fin de la transition. Dans ce cas, les rappels `done` sont requis pour les hooks `@enter` et `@leave`. Sinon, les hooks seront appelés de manière synchrone et la transition se terminera immédiatement.
Voici une démo utilisant la [bibliothèque GSAP](https://gsap.com/) pour réaliser les animations. Vous pouvez bien sûr utiliser toute autre bibliothèque d'animation de votre choix, par exemple [Anime.js](https://animejs.com/) ou [Motion One](https://motion.dev/) :
[Essayer en ligne](https://play.vuejs.org/#eNqNVMtu2zAQ/JUti8I2YD3i1GigKmnaorcCveTQArpQFCWzlkiCpBwHhv+9Sz1qKYckJ3FnlzvD2YVO5KvW4aHlJCGpZUZoB5a7Vt9lUjRaGQcnMLyEM5RGNbDA0sX/VGWpHnB/xEQmmZIWe+zUI9z6m0tnWr7ymbKVzAklQclvvFSG/5COmyWvV3DKJHTdQiRHZN0jAJbRmv9OIA432/UE+jODlKZMuKcErnx8RrazP8woR7I1FEryKaVTU8aiNdRfwWZTQtQwi1HAGF/YB4BTyxNY8JpaJ1go5K/WLTfhdg1Xq8V4SX5Xja65w0ovaCJ8Jvsnpwc+l525F2XH4ac3Cj8mcB3HbxE9qnvFMRzJ0K3APuhIjPefmTTyvWBAGvWbiDuIgeNYRh3HCCDNW+fQmHtWC7a/zciwaO/8NyN3D6qqap5GfVnXAC89GCqt8Bp77vu827+A+53AJrOFzMhQdMnO8dqPpMO74Yx4wqxFtKS1HbBOMdIX4gAMffVp71+Qq2NG4BCIcngBKk8jLOvfGF30IpBGEwcwtO6p9sdwbNXPIadsXxnVyiKB9x83+c3N9WePN9RUQgZO6QQ2sT524KMo3M5Pf4h3XFQ7NwFyZQpuAkML0doEtvEHhPvRDPRkTfq/QNDgRvy1SuIvpFOSDQmbkWTckf7hHsjIzjltkyhqpd5XIVNN5HNfGlW09eAcMp3J+R+pEn7L)
[Essayer en ligne](https://play.vuejs.org/#eNqNVFFvmzAQ/is3pimNlABNF61iaddt2tukvfRhk/xiwIAXsJF9pKmq/PedDTSwh7ZSFLjvzvd9/nz4KfjatuGhE0ES7GxmZIu3TMmm1QahtLyFwugGFu51wRQAU+Lok7koeFcjPDk058gvlv07gBHYGTVGALbSDwmg6USPnNzjtHL/jcBK5zZxxQwZavVNFNqIHwqF8RUAWs2jn4IffCfqQz+mik5lKLWi3GT1hagHRU58aAUSshpV2YzX4ncCcbjZDp099GcG6ZZnEh8TuPR8S0/oTJhQjmQryLUSU0rUU8a8M9wtoWZTQtIwi0nAGJ/ZB0BwKxJYiJpblFko1a8OLzbhdgWXy8WzP99109YCqdIJmgifyfYuzmUzfFF2HH56o/BjAldx/BbRo7pXHKMjGbrl1IcciWn9fyaNfC8YsIueR5wCFFTGUVAEsEs7pOmDu6yW2f6GBW5o4QbeuScLbu91WdZiF/VlvgEtujdcWek09tx3qZ+/tXAzQU1mA8mCoeicneO1OxKP9yM+4ElmLaEFr+2AecVEn8sDZOSrSzv/1qk+sgAOa1kMOyDlu4jK+j1GZ70E7KKJAxRafKzdazi26s8h5dm+NLpTeQLvP27S6+urz/7T5aaUao26TWATt0cPPsgcK3f6Q1wJWVY4AVJtcmHWhueyo89+G38guD+agT5YBf39s25oIv5arehu8krYkLAs8BeG86DfuANYUCG2NomiTrX7Msx0E7ncl0bnXT04566M4PQPykWaWw==)
## Réutiliser les transitions {#reusable-transitions}
Les transitions peuvent être réutilisées via le système de composants de Vue. Pour créer une transition réutilisable, nous pouvons créer un composant qui encapsule le composant `` et transmet le contenu de l'emplacement :
```vue{6} [MyTransition.vue]
```
Désormais, `MyTransition` peut être importé et utilisé comme la version native :
```vue-html
Hello
```
## Transition à l'apparition {#transition-on-appear}
Si vous souhaitez également appliquer une transition sur le rendu initial d'un nœud, vous pouvez ajouter la prop `appear` :
```vue-html
...
```
## Transition entre élements {#transition-between-elements}
En plus de basculer un élément avec `v-if` /`v-show`, nous pouvons également faire la transition entre deux éléments en utilisant `v-if` /`v-else` /`v-else-if`, tant que nous nous assurons qu'un seul élément est affiché à tout moment :
```vue-html
Edit
Save
Cancel
```
[Essayer en ligne](https://play.vuejs.org/#eNqdk8tu2zAQRX9loI0SoLLcFN2ostEi6BekmwLa0NTYJkKRBDkSYhj+9wxJO3ZegBGu+Lhz7syQ3Bd/nJtNIxZN0QbplSMISKNbdkYNznqCPXhcwwHW3g5QsrTsTGekNYGgt/KBBCEsouimDGLCvrztTFtnGGN4QTg4zbK4ojY4YSDQTuOiKwbhN8pUXm221MDd3D11xfJeK/kIZEHupEagrbfjZssxzAgNs5nALIC2VxNILUJg1IpMxWmRUAY9U6IZ2/3zwgRFyhowYoieQaseq9ElDaTRrkYiVkyVWrPiXNdiAcequuIkPo3fMub5Sg4l9oqSevmXZ22dwR8YoQ74kdsL4Go7ZTbR74HT/KJfJlxleGrG8l4YifqNYVuf251vqOYr4llbXz4C06b75+ns1a3BPsb0KrBy14Aymnerlbby8Vc8cTajG35uzFITpu0t5ufzHQdeH6LBsezEO0eJVbB6pBiVVLPTU6jQEPpKyMj8dnmgkQs+HmQcvVTIQK1hPrv7GQAFt9eO9Bk6fZ8Ub52Qiri8eUo+4dbWD02exh79v/nBP+H2PStnwz/jelJ1geKvk/peHJ4BoRZYow==)
## Modes des transitions {#transition-modes}
Dans l'exemple précédent, les éléments d'entrée et de sortie sont animés en même temps, et nous avons dû les appliquer `position: absolute` pour éviter le problème de mise en page lorsque les deux éléments sont présents dans le DOM.
Cependant, dans certains cas, ce n'est pas une option, ou ce n'est tout simplement pas le comportement souhaité. Nous pouvons vouloir que l'élément sortant soit animé en premier, et que l'élément entrant ne soit inséré **qu'après** que l'animation de départ soit terminée. Orchestrer manuellement de telles animations serait très compliqué - heureusement, nous pouvons activer ce comportement en passant à `` la prop `mode` :
```vue-html
...
```
Voici la démo précédente avec `mode="out-in"` :
`` prend également en charge `mode="in-out"`, bien qu'il soit beaucoup moins fréquemment utilisé.
## Transition entre composants {#transition-between-components}
`` peut également être utilisé autour des [composants dynamiques](/guide/essentials/component-basics#dynamic-components) :
```vue-html