Capitolo 5 di 11

Vue 3: gestire gli eventi con v-on (@click, $event, modificatori)

verificato il 7 Settembre 2026 · 6 min

Risposta rapida

v-on:click, o la sua scorciatoia @click, esegue del codice quando l'evento si verifica. Passa il nome di una funzione per ricevere l'evento nativo, oppure chiamala con i suoi argomenti e $event se ti servono entrambi. I modificatori .prevent, .stop, .once, .enter o .esc sostituiscono il codice ripetitivo di gestione degli eventi.

Alla fine di questo capitolo, saprai reagire ai clic, al passaggio del mouse e ai tasti della tastiera, passare argomenti ai tuoi gestori, recuperare l'evento nativo e usare i modificatori per scrivere meno codice.

Per ora l’applicazione mostra e basta. Non reagisce a niente. La direttiva v-on collega un listener di eventi a un elemento ed esegue del codice quando l’evento si verifica. Questo capitolo copre tutto quello che se ne fa ogni giorno: un clic, il passaggio del mouse, un tasto, con o senza argomenti, e i modificatori che evitano di scrivere preventDefault() a mano.

Il carrello

Aggiungi un contatore e un pulsante:

src/App.vue
<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>

Ascoltare un clic

v-on: seguito dal nome dell’evento, con il codice da eseguire tra virgolette:

src/App.vue
<button class="button" v-on:click="cart += 1">Ajouter au panier</button>

Clicca: il contatore sale. Il nome dell’evento è quello standard del DOM, senza prefisso: click, submit, input, keyup, mouseover.

Chiamare una funzione

Un’espressione inline va bene per un’operazione banale. Appena la logica supera una riga, scrivi una funzione:

src/App.vue
<script setup>
function addToCart() {
  cart.value += 1
}
</script>

<template>
  <button class="button" v-on:click="addToCart">Ajouter au panier</button>
</template>

Nota il .value nello script: stiamo manipolando la ref, non il valore già estratto. Nel template si scrive sempre {{ cart }}, senza .value.

Con o senza parentesi?

@click="addToCart" passa la funzione stessa: Vue la chiama con l’evento nativo come primo argomento. @click="addToCart()" la chiama senza argomenti. Qui funzionano entrambe. L’errore classico arriva quando la funzione si aspetta un valore: @click="updateImage(variant.image)" è corretto, ma dimenticare le parentesi passerebbe l’evento al posto del percorso dell’immagine.

La scorciatoia con la chiocciola

Come v-bind ha :, v-on ha @:

src/App.vue
<button class="button" @click="addToCart">Ajouter au panier</button>

È la scrittura che vedrai in tutta la documentazione e nel resto di questo tutorial.

Passare un argomento

Facciamo cambiare l’immagine al passaggio del mouse su un colore. La funzione riceve il percorso dell’immagine della variante sotto il cursore:

src/App.vue
<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>

Passa il mouse su «Rouge»: l’immagine diventa rossa. Qui si combinano due meccanismi, il ciclo del capitolo 4 e il binding di attributo del capitolo 2.

Recuperare l’evento nativo

Senza argomenti, la funzione riceve l’evento del DOM. Con degli argomenti, chiedilo esplicitamente con $event:

html
<button @click="voir">Sans argument</button>
<button @click="voirAvec('bleu', $event)">Avec arguments</button>
javascript
function voir(event) {
  console.log(event.target)
}

function voirAvec(couleur, event) {
  console.log(couleur, event.target)
}

L’oggetto ricevuto è l’evento nativo del browser, senza involucro: event.target, event.key, event.preventDefault() funzionano come in JavaScript puro.

I modificatori di evento

Vue aggiunge dei suffissi che evitano il codice ripetitivo di gestione degli eventi:

html
<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 -->

La lista completa, con quello che ogni modificatore sostituisce:

Modificatore Equivalente JavaScript Uso tipico
.prevent event.preventDefault() un form che non deve ricaricare la pagina
.stop event.stopPropagation() un pulsante dentro una card cliccabile: il clic non risale alla card
.self if (event.target !== event.currentTarget) return chiudere una finestra modale al clic sullo sfondo, non sul suo contenuto
.once addEventListener(…, { once: true }) un pulsante «Ordina» che non deve inviare due volte
.capture addEventListener(…, { capture: true }) intercettare l’evento prima dei figli
.passive addEventListener(…, { passive: true }) scorrimento e tocco su mobile, per non bloccare il rendering

I modificatori si concatenano e si leggono da sinistra a destra: @click.stop.prevent ferma la propagazione, poi annulla il comportamento predefinito. Quest’ordine conta con .self: @click.self.prevent annulla il comportamento predefinito solo per i clic sull’elemento stesso, @click.prevent.self lo annulla per tutti i clic, figli compresi.

@submit.prevent servirà al capitolo 10 per impedire il ricaricamento della pagina all’invio del form.

Modificatori di tasto e di mouse

Sugli eventi da tastiera, un modificatore filtra il tasto. Vue accetta qualsiasi nome di tasto esposto da KeyboardEvent.key, scritto in kebab-case, più qualche alias:

html
<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 -->

Gli alias disponibili: .enter, .tab, .delete (Canc e Backspace), .esc, .space, .up, .down, .left, .right. I tasti di sistema .ctrl, .alt, .shift e .meta si combinano con gli altri. E .exact pretende che nessun altro tasto di sistema sia premuto:

html
<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 -->

Per il mouse, .left, .right e .middle filtrano il pulsante: @click.right.prevent="menuContextuel" sostituisce il menu del browser con il tuo.

Più gestori sullo stesso evento

Un evento può far partire più funzioni, separate da virgole. Ogni funzione viene allora chiamata con le parentesi:

html
<button @click="addToCart(), trackClick('ajout-panier')">Ajouter au panier</button>

Oltre le due chiamate non è più leggibile: scrivi una funzione che chiama le altre.

  • v-on:click o @click: un’espressione inline per un’operazione banale, altrimenti una funzione.
  • Senza parentesi, la funzione riceve l’evento nativo; con degli argomenti, $event lo passa in più.
  • .prevent, .stop, .self, .once sostituiscono il codice ripetitivo; i modificatori di tasto filtrano la tastiera; .exact blocca le combinazioni.
  • Nello script lo stato si modifica con .value; nel template, senza.
In Options API

Le funzioni vivono nell’opzione methods e accedono allo stato con this: methods: { addToCart() { this.cart += 1 } }. Il template, invece, non cambia.

Gli eventi di questo capitolo vengono dal DOM. Perché un componente figlio avvisi il suo genitore, Vue propone gli eventi personalizzati con emit: è l’argomento del capitolo 9, approfondito nella guida completa a Vue emit.

EsercizioAggiungi un pulsante «Togli dal carrello» che decrementa il contatore senza mai scendere sotto zero. Poi sostituisci il passaggio del mouse con un clic sui colori, e confronta la sensazione.

Errori frequenti

Dimenticare .value in una funzione Nello script, cart += 1 non fa niente di utile su una ref: scrivi cart.value += 1.
Parentesi mancanti con un argomento @click="updateImage" passa l'evento nativo al posto del valore atteso. Con un argomento, chiama la funzione: @click="updateImage(variant.image)".
Recuperare l'evento quando si passa già un argomento Va chiesto esplicitamente con $event: @click="faire('bleu', $event)".
Concatenare i modificatori nell'ordine sbagliato @click.prevent.self impedisce il comportamento predefinito di tutti i clic, @click.self.prevent solo di quelli il cui bersaglio è l'elemento stesso. L'ordine si legge da sinistra a destra.
Usare .passive con .prevent .passive promette al browser di non chiamare preventDefault(); combinato con .prevent, il browser ne ignora uno dei due e mostra un avviso.
Newsletter

I nuovi test, tutorial e progetti, via e-mail.

Test riproducibili, codice versionato, risultati datati. Mai spam.