Les événements de composant
Cette page suppose que vous avez déjà lu les principes fondamentaux des composants. Lisez-les d'abord si vous débutez avec les composants.
Émettre et écouter des événements
Un composant peut émettre des événements personnalisés directement à partir du template (par exemple, dans un gestionnaire d'événement v-on
) à l'aide de la méthode native $emit
:
template
<!-- MyComponent -->
<button @click="$emit('someEvent')">Cliquez-Moi</button>
Le composant parent peut alors l'écouter en utilisant v-on
:
template
<MyComponent @some-event="callback" />
Le modificateur .once
est également pris en charge sur les écouteurs d'événements de composants :
template
<MyComponent @some-event.once="callback" />
Comme les composants et les props, les noms d'événements fournissent une transformation de casse automatique. Notez que nous avons émis un événement camelCase
, mais que nous pouvons l'écouter à l'aide d'un écouteur kebab-case
dans le parent. Comme pour la casse des props, nous vous recommandons d'utiliser des noms d'écouteurs d'événement au format kebab-case
dans les templates.
TIP
Contrairement aux événements DOM natifs, les événements émis par les composants ne se propagent pas au delà de leur parent direct. Vous ne pouvez écouter que les événements émis par un composant enfant direct. S'il est nécessaire de communiquer entre des composants frères ou profondément imbriqués, utilisez un bus d'événements externe ou une solution de gestion d'état global.
Arguments d'événement
Il est parfois utile d'émettre une valeur spécifique avec un événement. Par exemple, nous pouvons vouloir que le composant <BlogPost>
soit en charge d'agrandir plus ou moins le texte. Dans ces cas, nous pouvons passer des arguments supplémentaires à $emit
pour fournir cette valeur :
template
<button @click="$emit('increaseBy', 1)">
Increase by 1
</button>
Ensuite, lorsque nous écoutons l'événement dans le composant parent, nous pouvons utiliser une fonction fléchée comme écouteur, ce qui nous permet d'accéder à l'argument de l'événement :
template
<MyButton @increase-by="(n) => count += n" />
Ou, si le gestionnaire d'événements est une méthode :
template
<MyButton @increase-by="increaseCount" />
Ensuite, la valeur sera transmise comme premier paramètre de cette méthode :
js
function increaseCount(n) {
count.value += n
}
TIP
Tous les arguments supplémentaires passés à $emit()
après le nom de l'événement seront transmis à l'écouteur. Par exemple, avec $emit('foo', 1, 2, 3)
la fonction d'écoute recevra trois arguments.
Déclaration des événements émis
Les événements émis peuvent être explicitement déclarés sur le composant via la macro defineEmits()
:
vue
<script setup>
defineEmits(['inFocus', 'submit'])
</script>
La méthode $emit
que nous avons utilisée dans le <template>
n'est pas accessible dans la section <script setup>
d'un composant, mais defineEmits()
renvoie une fonction équivalente que nous pouvons utiliser à la place :
vue
<script setup>
const emit = defineEmits(['inFocus', 'submit'])
function buttonClick() {
emit('submit')
}
</script>
La macro defineEmits()
ne peut pas être utilisée dans une fonction, elle doit être placée directement dans <script setup>
, comme dans l'exemple ci-dessus.
Si vous utilisez une fonction setup
explicite au lieu de <script setup>
, les événements doivent être déclarés à l'aide de l'option emits
, et la fonction emit
est exposée dans le contexte de setup()
:
js
export default {
emits: ['inFocus', 'submit'],
setup(props, ctx) {
ctx.emit('submit')
}
}
Comme pour les autres propriétés du contexte de setup()
, emit
peut être déstructurée en toute sécurité :
js
export default {
emits: ['inFocus', 'submit'],
setup(props, { emit }) {
emit('submit')
}
}
L'option emits
et la macro defineEmits()
supportent également une syntaxe avec un objet. Si vous utilisez TypeScript, vous pouvez utiliser les arguments, ce qui nous permet d'effectuer une validation à l'exécution du contenu des événements émis :
vue
<script setup lang="ts">
const emit = defineEmits({
submit(payload: { email: string, password: string }) {
// renvoie `true` ou `false` pour indiquer
// que la validation a réussi/échoué
}
})
</script>
Si vous utilisez TypeScript avec <script setup>
, il est également possible de déclarer des événements émis à l'aide d'annotations de type :
vue
<script setup lang="ts">
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
</script>
Plus de détails : Typer les données émises par les composants
Bien que facultatif, il est recommandé de définir tous les événements émis afin de mieux documenter le fonctionnement d'un composant. Cela permet également à Vue d'exclure les écouteurs connus des attributs implicitement déclarés (fallthrough attributes), évitant ainsi les problèmes liés aux cas à la marge causés par des événements DOM envoyés manuellement par du code tiers.
TIP
Si un événement natif (par exemple, click
) est défini dans l'option emits
, l'écouteur n'écoutera alors que les événements click
émis par le composant et ne réagira plus aux événements click
natifs.
Validation des événements
Semblable à la validation de type de prop, un événement émis peut être validé s'il est défini avec la syntaxe utilisant un objet au lieu d'un tableau.
Pour ajouter une validation, l'événement se voit attribuer une fonction qui reçoit les arguments passés à l'appel de emit
et renvoie un booléen pour indiquer si l'événement est valide ou non.
vue
<script setup>
const emit = defineEmits({
// Pas de validation
click: null,
// Validation de l'événement soumis
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
</script>