Dopo aver introdotto alcune direttive fra cui v-bind, che consente di assegnare un’espressione javascript agli attributi degli elementi HTML, illustriamo il funzionamento della direttiva v-on grazie alla quale è possibile intercettare e gestire gli eventi del DOM.
La direttiva v-on
Vediamo subito un primo semplice esempio in cui generiamo un numero casuale in seguito alla pressione di un pulsante. Per questo creiamo due file index.html e app.js che contengono le seguenti porzioni di codice.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue.js: esempio gestione eventi</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main id="root">
<div class="display">
<span>{{ randomNumber }}</span>
</div>
<button
v-on:click="randomNumber = Math.round(Math.random() * 5)">
Random Number
</button>
</main>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="app.js"></script>
</body>
</html>
const vm = new Vue({
el: '#root',
data: {
randomNumber: 0
}
});
Alla direttiva v-on dobbiamo passare come argomento il nome dell’evento che vogliamo intercettare. Al verificarsi di quest’ultimo, Vue provvede ad eseguire l’istruzione compresa fra doppie virgolette. Nel caso particolare assegniamo alla proprietà randomNumber un valore casuale compreso fra 0 e 5 che viene mostrato sullo schermo usando la tecnica dell’interpolazione. Vue provvede ad aggiornare automaticamente l’applicazione ogni volta che randomNumber cambia.
Sintassi abbreviata per la direttiva v-on
La direttiva v-on, insieme a v-bind, è sicuramente una delle direttive usate più frequentemente. Per questo motivo è stata introdotta una sintassi alternativa abbreviata. Possiamo sostituire v-on:nomeEvento con @nomeEvento.
<button
@click="randomNumber = Math.round(Math.random() * 5)">
Random Number
</button>
Da questo momento in poi, come già fatto per v-bind
, utilizzeremo la sintassi abbreviata anche per v-on
.
Gestire gli eventi con dei metodi
Nell’esempio visto in precedenza alla direttiva v-on abbiamo passato direttamente l’istruzione da eseguire al verificarsi dell’evento click. Già in questo semplice caso l’istruzione inserita direttamente nel markup HTML è piuttosto lunga e difficile da leggere. Possiamo semplificare il codice introducendo un’altra utile funzionalità di Vue, ovvero la proprietà methods che consente di definire dei metodi di un’istanza. Basterà quindi passare uno dei metodi direttamente alla direttiva v-on. Al verificarsi di un certo evento, il metodo sarà eseguito ed eventuali modifiche delle proprietà saranno poi replicate all’interno dell’applicazione.
Ecco come cambia l’esempio visto in precedenza facendo uso dei metodi.
const vm = new Vue({
el: '#root',
data: {
randomNumber: 0
},
// definiamo i metodi dell'istanza
methods: {
generateRandomNumber(event) {
// All'interno dei metodi,
// Vue fa in modo che
// 'this' si riferisca all'istanza 'vm'
// cosicché sia possibile accedere alle proprietà
// dell'oggetto 'data'
this.randomNumber = Math.round(Math.random() * 5);
}
}
});
<main id="root">
<div class="display">
<span>{{ randomNumber }}</span>
</div>
<button
@click="generateRandomNumber">
Random Number
</button>
</main>
All’oggetto delle opzioni, col quale configuriamo la nuova istanza Vue, abbiamo aggiunto una nuova proprietà methods in cui definiamo i metodi associati all’istanza. Nel caso specifico passiamo poi il nome del metodo generateRandomNumber()
a @click
in modo da essere eseguito ogni volta che viene premuto il pulsante ‘Random Number’. Notiamo un aspetto importante: nel frammento di codice HTML all’evento click associamo un riferimento al metodo che riceve dunque come primo argomento un oggetto contenente tutte le informazioni in merito all’evento del DOM che si è verificato (MouseEvent Object).
Nel file app.js abbiamo poi definito il metodo generateRandomNumber()
che fa parte dell’oggetto methods usando la nuova sintassi introdotta a partire da ES2015 per i metodi di un oggetto. In alternativa avremmo potuto usare la sintassi che assegna una funzione al nome di un metodo.
const vm = new Vue({
el: '#root',
data: {
randomNumber: 0
},
// definiamo i metodi dell'istanza
methods: {
generateRandomNumber: function(event) {
// All'interno dei metodi,
// Vue fa in modo che
// 'this' si riferisca all'istanza 'vm'
// cosicché sia possibile accedere alle proprietà
// dell'oggetto 'data'
this.randomNumber = Math.round(Math.random() * 5);
}
}
});
Dobbiamo però prestare particolare attenzione al fatto che, per permettere l’accesso diretto alle proprietà dell’oggetto data, Vue fa in modo che all’interno di ogni metodo this
si riferisca all’istanza base piuttosto che all’oggetto methods. Per questa ragione non è possibile definire i metodi attraverso le funzioni a freccia (Arrow Function).
/* ATTENZIONE!!!
* -- ESEMPIO ERRATO --
*/
const vm = new Vue({
el: '#root',
data: {
randomNumber: 0
},
// definiamo i metodi dell'istanza
methods: {
// Arrow Function: () => {}
generateRandomNumber: (event) => {
// NON è più possibile accedere alla proprietà randomNumber
// perché `this` punta ora all'oggetto globale Window
this.randomNumber = Math.round(Math.random() * 5);
}
}
});
Gestori di eventi con argomenti
Finora abbiamo visto come assegnare alla direttiva v-on un riferimento ad un metodo che sarà poi invocato al verificarsi di un determinato evento. A volte può essere però necessario passare degli argomenti ad un metodo direttamente all’interno del codice HTML. In questi casi andremo a specificare gli argomenti chiamando il metodo all’interno dell’istruzione che viene assegnata a v-on.
new Vue({
el: '#root',
methods: {
id: function (buttonId) {
console.info(`Pulsante ${buttonId}`);
}
}
});
<div id="root">
<button @click="id(1)">Pulsante 1</button>
<button @click="id(2)">Pulsante 2</button>
<button @click="id(3)">Pulsante 3</button>
</div>
Nel caso in cui ci fosse anche bisogno dell’oggetto relativo all’evento del DOM che si è verificato, possiamo passarlo ad un metodo come ultimo argomento usando la variabile speciale $event definita da Vue.
const vm = new Vue({
el: '#root',
methods: {
validate(inputName, event) {
console.log(`Validating input field ${inputName}...`);
console.log(`Current value: ${event.target.value}`);
}
}
});
<div id="root">
<input
type="text"
@input="validate('Name', $event)">
</div>
La direttiva v-on e gli eventi dinamici
Una delle funzionalità più interessanti di Vue, che possiamo sfruttare anche con la direttiva v-on, è rappresentata dagli argomenti dinamici delle direttive. Finora infatti abbiamo passato sia alla direttiva v-bind che a v-on degli argomenti statici. Nell’esempio appena illustrato, a v-on
passiamo come argomento il nome dell’evento ‘click’.
A partire dalla versione 2.6.0, è possibile usare un’espressione Javascript racchiusa fra parentesi quadre come argomento di una direttiva.
<input type="text" @[event]="validate">
In questo modo siamo in grado di cambiare in maniera dinamica quale evento deve avviare l’esecuzione della funzione validate
. Se per esempio la proprietà event è pari a ‘input’, la validazione del campo sarà eseguita ogni volta che si inserisce un nuovo carattere. Al contrario possiamo assegnare alla proprietà event la stringa ‘change’ e fare in modo che la validazione avvenga al verificarsi di tale evento, ovvero quando il valore del campo subisce una variazione e il campo stesso perde il focus.
Per meglio chiarire quanto appena illustrato a proposito degli argomenti dinamici per le direttive, realizziamo un altro semplice esempio.
Come per i casi precedenti, all’interno di una nuova cartella inseriamo i soliti due file index.html e app.js. In quest’ultimo creiamo una nuova istanza base con due proprietà di tipo stringa event ed errorMsg. Nellla prima conserviamo il nome dell’evento in seguito al quale vogliamo validare un campo di testo, la seconda contiene un eventuale messaggio di errore. Aggiugiamo quindi un metodo validate() che riceve come argomento un evento, preleva il valore corrente del campo di testo (event.target.value) ed effettua una banale validazione usando un’espressione regolare. In caso di errore assegna alla proprietà errorMsg una stringa per segnalare all’utente che il campo di testo contiene dei valori non validi.
const vm = new Vue({
el: "#root",
data: {
event: 'input',
errorMsg: ''
},
// definiamo i metodi dell'istanza
methods: {
validate(event) {
const inputValue = event.target.value;
const pattern = /^[a-zA-Z]+$/;
if (pattern.test(inputValue) === false) {
this.errorMsg = 'campo non valido';
} else {
this.errorMsg = '';
}
}
}
});
Nel file index.html inseriamo un form con un campo di testo che vogliamo validare ed un selettore per scegliere il tipo di evento che avvia il processo di validazione.
<main id="root">
<form>
<!-- selettore -->
<fieldset>
<legend>Seleziona quando validare il campo sottostante</legend>
<input
type="radio"
id="input-selector"
value="input"
:checked="event === 'input'"
@change="event = 'input'">
<label for="input-selector">Evento Input</label>
<input
type="radio"
id="change-selector"
value="change"
:checked="event === 'change'"
@change="event = 'change'">
<label for="change-selector">Evento Change</label>
</fieldset>
<!-- input di testo da validare -->
<input type="text" @[event]="validate" placeholder="Inserisci del testo">
<!-- eventuale messaggio di errore -->
<div class="error">{{ errorMsg }}</div>
</form>
</main>
Per la direttiva v-on, applicata all’input di testo, abbiamo usato un argomento dinamico rappresentato dalla proprietà event definita nell’istanza base. Selezionando uno dei pulsanti di tipo radio, abbiamo la facoltà cambiare il valore di event assegnando rispettivamente le stringhe ‘input’ e ‘change’. L’attributo checked necessita invece di un valore booleano. Per questa ragione utilizziamo la direttiva v-bind. Vue compara il valore della proprietà event con le due stringhe ‘input’ e ‘change’, il risultato (true o false) viene poi assegnato all’attributo checked che determina visivamente quale dei due pulsanti radio è attualmente selezionato.
In questo modo decidiamo quando deve essere effettuato il processo di validazione, se selezioniamo il primo pulsante radio, il metodo validate()
viene invocato all’inserimento di ogni carattere nel campo di input. Quando la proprietà event assume invece il valore ‘change’, la validazione avviene solo se il campo di testo perde il focus e solo se il suo valore è stato modificato.
Per gli input di tipo radio abbiamo usato la direttiva v-on in combinazione con v-bind. Nelle prossime lezioni vedremo come sostituirli attraverso la direttiva v-model.
Modificatori di eventi
Dopo aver illustrato il funzionamento degli eventi dinamici, passiamo ad un’altra utile funzionalità, ovvero i modificatori di eventi che appendiamo direttamente all’argomento passato alla direttiva v-on. I modificatori di eventi rappresentano un modo alternativo e più veloce per semplificare la definizione dei metodi dell’istanza.
Per esempio capita piuttosto frequentemente di dover invocare event.preventDefault()
all’interno di un metodo. Il caso tipico è per bloccare il normale invio di un form ed eseguire invece delle chiamate AJAX.
<!-- usiamo il modificatore .prevent invece di invocare -->
<!-- event.preventDefault() nel metodo handleFormSubmission() -->
<form @submit.prevent="handleFormSubmission"></form>
Altri modificatori utili sono .stop
che svolge la stessa funzione di event.stopPropagation()
e .once
che consente di attivare un evento una sola volta. Il modificatore .self
invoca invece la funzione che gestisce l’evento solo se event.target coincide con l’elemento su cui è applicata la direttiva v-on. Ciò significa che vengono scartati gli eventi che si propagano dagli elementi discendenti.
È comunque possibile concatenare più modificatori come mostrato sotto.
<!-- concatenare i modificatori -->
<a @click.stop.prevent="handleClick"></a>
Modificatori per eventi generati dal mouse
A partire dalla versione 2.2.0 sono stati introdotti tre modificatori per limitare il tipo di evento da gestire in seguito al click del mouse.
.left
.middle
.right
<main id="root">
<button @click.prevent.right="onClick">click</button>
</main>
const vm = new Vue({
el: "#root",
// definiamo i metodi dell'istanza
methods: {
onClick(event) {
// tramite modificatore .right
// onClick viene invocato solo al click
// del tasto destro del mouse
console.log(event.button); // stampa solo 2
}
}
});
Nell’esempio appena presentato, il metodo onClick viene invocato solo in seguito al click destro del mouse grazie all’uso del modificatore .right. Abbiamo anche utilizzato il modificatore .prevent per evitare che venga aperto un menù contestuale.
Gestire gli eventi da tastiera
Per concludere questa lezione presentiamo i modificatori per gli eventi da tastiera che permettono di verificare l’immissione di specifici caratteri appendendo il nome di un tasto direttamente all’evento associato alla direttiva v-on.
I tasti accettati sono tutti quelli esposti attraverso KeyboardEvent.key
, esprimendo però i nomi secondo la notazione kebak-case.
new Vue({
el: "#app",
data: {
key: ''
},
methods: {
onKeyUp(event) {
this.key = event.key;
}
}
})
<div id="app">
<input type="text" @keyup.a.e.i.o.u="onKeyUp">
<span>Ultima vocale digitata: {{ key }}</span>
</div>
Nell’esempio riportato sopra, onKeyUp()
viene invocato solo se vengono immesse delle vocali all’interno del campo di input. Tutti gli altri caratteri saranno ignorati.
Possiamo anche registrare un gestore di eventi nel caso in cui vengano premuti altri tasti come il tasto ‘Invio’ o i tasti freccia. Anche per questi occorre usare l’opportuno modificatore come mostrato sotto.
<div id="app">
<input type="text" @keyup.enter.arrow-up="onKeyUp">
<span>Ultimo tasto premuto: {{ key }}</span>
</div>
Abbiamo dunque modificato l’esempio precedente in modo che il metodo onKeyUp()
venga invocato solo quando viene premuto uno dei due tasti: ‘invio’ o ‘freccia verso l’alto’.
Vue consente infine di usare dei modificatori di sistema per gestire eventuali combinazioni di tasti.
I quattro modificatori riportati sotto consentono di invocare un gestore di eventi quando vengono premuti insieme ad altri tasti della tastiera o del mouse.
.ctrl
.alt
.shift
.meta
<!-- Ctrl + Click -->
<span v-on:click.ctrl="onClick">Lorem Ipsum</span>
<!-- Alt + a -->
<input v-on:keydown.alt.a="onKeyDown">
A seconda della tastiera e del sistema operativo, il modificatore .meta
si rifesce al tasto Command su MacOS o Windows key.
<!-- Command+i oppure WindowsKey+i -->
<input type="text" @keydown.meta.i="handler">
Nella versione 2.5 di Vue.js è stato infine introdotto il modificatore .exact
per specificare l’esatta combinazione dei modificatori di sistema che generano un evento.
<button v-on:click.alt="handler">Click</button>
Se infatti consideriamo l’esempio mostrato sopra, il metodo handler
viene comunque invocato per entrambi le combinazioni: Alt+Click
e Alt+Shift+Click
.
Per assicurarsi che soltanto Alt+Click
attivi un evento, dovremo quindi usare il modificatore .exact
.
<button v-on:click.alt.exact="handler">A</button>
Conclusioni
In questa lezione abbiamo visto come intercettare gli eventi del DOM attraverso la direttiva v-on che può essere anche usata con la sintassi abbreviata @. Abbiamo poi introdotto una nuova proprietà di un’istanza Vue, ovvero ‘methods’ che consente di definire dei metodi che possiamo passare anche alla direttiva v-on
in modo da essere eseguiti al verificarsi di un certo evento. Fra le funzionalità offerte da v-on
, vi è la capacità di intercettare la pressione di determinati tasti della tastiera o del mouse attraverso l’uso di modificatori predefiniti che appendiamo al nome dell’evento. Sempre attraverso a dei modificatori siamo in grado di indicare a Vue come deve comportarsi quando viene lanciato un determinato evento, specificando per esempio se interrompere la propagazione dell’evento stesso o se eseguire una certa istruzione una volta sola. La direttiva v-on presenta infine una sintassi specifica per gestire degli eventi dinamici.