Vue 3 v-on: events afhandelen met @click, $event en modifiers
geverifieerd op 7 september 2026 · 6 min
v-on:click, of de shorthand @click, voert code uit zodra het event optreedt. Geef de naam van een functie door om het native event te ontvangen, of roep haar aan met haar argumenten plus $event als je beide nodig hebt. De modifiers .prevent, .stop, .once, .enter en .esc vervangen de terugkerende code voor eventafhandeling.
Voorlopig toont de applicatie alleen. Ze reageert nergens op. De directive v-on hangt een event listener aan een element en voert code uit zodra het event optreedt. Dit hoofdstuk behandelt alles wat je er dagelijks mee doet: een klik, een hover, een toets, met of zonder argument, en de modifiers die je besparen om preventDefault() met de hand te schrijven.
Het winkelmandje
Voeg een teller en een knop toe:
<script setup>
import { ref } from 'vue'
const product = ref('T-Shirt')
const image = ref('/images/t-shirt-bleu.svg')
const inventory = ref(100)
const cart = ref(0)
const details = ref(['60 % coton', '30 % laine', '10 % polyester'])
const variants = ref([
{ id: 2234, color: 'Bleu', image: '/images/t-shirt-bleu.svg' },
{ id: 2235, color: 'Rouge', image: '/images/t-shirt-rouge.svg' }
])
</script>
<template>
<div class="product-display">
<div class="cart">Panier ({{ cart }})</div>
…
<button class="button">Ajouter au panier</button>
</div>
</template>Naar een klik luisteren
v-on: gevolgd door de naam van het event, met de uit te voeren code tussen aanhalingstekens:
<button class="button" v-on:click="cart += 1">Ajouter au panier</button>Klik: de teller loopt op. De naam van het event is die van het standaard-DOM, zonder prefix: click, submit, input, keyup, mouseover.
Een functie aanroepen
Voor een triviale bewerking volstaat een inline-expressie. Zodra de logica langer is dan één regel, schrijf je een functie:
<script setup>
function addToCart() {
cart.value += 1
}
</script>
<template>
<button class="button" v-on:click="addToCart">Ajouter au panier</button>
</template>Let op de .value in het script: we werken met de ref, niet met de uitgepakte waarde. In de template schrijf je altijd {{ cart }}, zonder .value.
@click="addToCart" geeft de functie zelf door: Vue roept haar aan met het native event als eerste argument. @click="addToCart()" roept haar aan zonder argument. Hier werken beide. De klassieke fout duikt op zodra de functie een waarde verwacht: @click="updateImage(variant.image)" is correct, maar zonder de haakjes zou je het event doorgeven in plaats van het pad naar de afbeelding.
Het apenstaartje als shorthand
Net zoals v-bind zijn : heeft, heeft v-on zijn @:
<button class="button" @click="addToCart">Ajouter au panier</button>Dit is de schrijfwijze die je in de hele documentatie en in de rest van deze tutorial tegenkomt.
Een argument meegeven
Laat de afbeelding veranderen zodra je over een kleur zweeft. De functie krijgt het pad van de afbeelding van de variant onder de muis:
<script setup>
function updateImage(variantImage) {
image.value = variantImage
}
</script>
<template>
<div
v-for="variant in variants"
:key="variant.id"
@mouseover="updateImage(variant.image)"
>
{{ variant.color }}
</div>
</template>Zweef over “Rouge”: de afbeelding wordt rood. Twee mechanismen komen hier samen, de lus uit hoofdstuk 4 en de attribuutbinding uit hoofdstuk 2.
Het native event ophalen
Zonder argument krijgt de functie het DOM-event. Geef je zelf argumenten mee, vraag het dan expliciet op met $event:
<button @click="voir">Sans argument</button>
<button @click="voirAvec('bleu', $event)">Avec arguments</button>function voir(event) {
console.log(event.target)
}
function voirAvec(couleur, event) {
console.log(couleur, event.target)
}Het object dat je krijgt, is het native event van de browser, zonder omhulsel: event.target, event.key en event.preventDefault() werken net als in pure JavaScript.
De event-modifiers
Vue biedt achtervoegsels die je het terugkerende afhandelingswerk besparen:
<form @submit.prevent="envoyer">…</form> <!-- event.preventDefault() -->
<div @click.stop="…">…</div> <!-- event.stopPropagation() -->
<div @click.self="…">…</div> <!-- seulement si la cible est cet élément -->
<button @click.once="…">…</button> <!-- une seule fois -->
<input @keyup.enter="valider"> <!-- seulement la touche Entrée -->De volledige lijst, met wat elke modifier vervangt:
| Modifier | JavaScript-equivalent | Typisch gebruik |
|---|---|---|
.prevent | event.preventDefault() | een formulier dat de pagina niet mag herladen |
.stop | event.stopPropagation() | een knop in een klikbare kaart: de klik gaat niet door naar de kaart |
.self | if (event.target !== event.currentTarget) return | een modaal venster sluiten bij een klik op de achtergrond, niet op de inhoud |
.once | addEventListener(…, { once: true }) | een knop “Bestellen” die niet twee keer mag versturen |
.capture | addEventListener(…, { capture: true }) | het event onderscheppen vóór de kinderen |
.passive | addEventListener(…, { passive: true }) | scrollen en aanraken op mobiel, om het renderen niet te blokkeren |
Modifiers ketenen zich aan elkaar en worden van links naar rechts gelezen: @click.stop.prevent stopt eerst de propagatie en annuleert dan het standaardgedrag. Die volgorde telt bij .self: @click.self.prevent annuleert het standaardgedrag alleen voor kliks op het element zelf, @click.prevent.self voor alle kliks, kinderen inbegrepen.
@submit.prevent komt in hoofdstuk 10 van pas om te voorkomen dat de pagina herlaadt wanneer het formulier wordt verstuurd.
Toets- en muismodifiers
Bij toetsenbordevents filtert een modifier op de toets. Vue accepteert elke toetsnaam die KeyboardEvent.key blootgeeft, geschreven in kebab-case, plus een paar aliassen:
<input @keyup.enter="valider">
<input @keyup.esc="annuler">
<input @keydown.tab="suivant">
<input @keyup.page-down="pageSuivante"> <!-- KeyboardEvent.key === 'PageDown' -->
<input @keydown.ctrl.enter="envoyer"> <!-- Ctrl + Entrée -->De beschikbare aliassen: .enter, .tab, .delete (Delete en Backspace), .esc, .space, .up, .down, .left, .right. De systeemtoetsen .ctrl, .alt, .shift en .meta combineren met de andere. En .exact eist dat geen enkele andere systeemtoets ingedrukt is:
<button @click.ctrl="ouvrir">…</button> <!-- Ctrl + clic, même si Shift est aussi enfoncé -->
<button @click.ctrl.exact="ouvrir">…</button> <!-- Ctrl + clic, et rien d'autre -->
<button @click.exact="ouvrir">…</button> <!-- clic sans aucune touche système -->Voor de muis filteren .left, .right en .middle op de knop: @click.right.prevent="menuContextuel" vervangt het menu van de browser door het jouwe.
Meerdere handlers op hetzelfde event
Eén event kan meerdere functies starten, gescheiden door komma’s. Elke functie wordt dan mét haakjes aangeroepen:
<button @click="addToCart(), trackClick('ajout-panier')">Ajouter au panier</button>Voorbij twee aanroepen is dit niet meer leesbaar: schrijf dan één functie die de andere aanroept.
Samenvatting
v-on:clickof@click: een inline-expressie voor een triviale bewerking, anders een functie.- Zonder haakjes krijgt de functie het native event; met argumenten geeft
$eventhet er extra bij. .prevent,.stop,.selfen.oncevervangen terugkerende code; de toetsmodifiers filteren het toetsenbord;.exactzet de combinaties vast.- In het script pas je de state aan via
.value; in de template niet.
De functies staan in de optie methods en bereiken de state via this: methods: { addToCart() { this.cart += 1 } }. De template zelf verandert niet.
De events uit dit hoofdstuk komen van het DOM. Om een kindcomponent zijn ouder te laten waarschuwen, biedt Vue eigen events met emit: dat is het onderwerp van hoofdstuk 9, uitgewerkt in de complete gids over Vue emit.
Veelgemaakte fouten
cart += 1 niets zinnigs op een ref: schrijf cart.value += 1.@click="updateImage" geeft het native event door in plaats van de verwachte waarde. Met een argument roep je de functie aan: @click="updateImage(variant.image)".$event: @click="faire('bleu', $event)".@click.prevent.self blokkeert het standaardgedrag van alle kliks, @click.self.prevent alleen van de kliks waarvan het element zelf het doelwit is. De volgorde lees je van links naar rechts..passive belooft de browser dat je preventDefault() niet aanroept; samen met .prevent negeert de browser er één van beide en toont hij een waarschuwing.