Passer au contenu

Gestion des évènements

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')">click me</button>

La méthode $emit() est également disponible sur l'instance du composant avec this.$emit() :

js
export default {
  methods: {
    submit() {
      this.$emit('someEvent')
    }
  }
}

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
methods: {
  increaseCount(n) {
    this.count += n
  }
}
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()l'option emits :

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')
  }
}
js
export default {
  emits: ['inFocus', 'submit']
}

L'option emits prend également en charge une syntaxe avec objet, ce qui nous permet d'effectuer une validation à l'exécution du contenu des évènements émis :

vue
<script setup>
const emit = defineEmits({
  submit(payload) {
    // 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

js
export default {
  emits: {
    submit(payload) {
      // renvoie `true` ou `false` pour indiquer
      // que la validation a réussi/échoué
    }
  }
}

Voir également : 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 this.$emitemit 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>
js
export default {
  emits: {
    // 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
      }
    }
  },
  methods: {
    submitForm(email, password) {
      this.$emit('submit', { email, password })
    }
  }
}
Gestion des évènementsa chargé