Vue 3 v-on: gerir eventos com @click, $event e modificadores
verificado a 7 Setembro 2026 · 6 min
v-on:click, ou o seu atalho @click, executa código quando o evento acontece. Passa o nome de uma função para receberes o evento nativo, ou chama-a com os seus argumentos e o $event se precisares dos dois. Os modificadores .prevent, .stop, .once, .enter ou .esc dispensam o código repetitivo de gestão de eventos.
Por agora, a aplicação mostra. Não reage a nada. A diretiva v-on liga um listener de evento a um elemento e executa código quando esse evento acontece. Este capítulo cobre tudo o que se faz com ela no dia a dia: um clique, a passagem do rato, uma tecla, com ou sem argumento, e os modificadores que evitam escrever preventDefault() à mão.
O carrinho
Acrescenta um contador e um botão:
<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>Escutar um clique
v-on: seguido do nome do evento, com o código a executar entre aspas:
<button class="button" v-on:click="cart += 1">Ajouter au panier</button>Clica: o contador sobe. O nome do evento é o do DOM padrão, sem prefixo: click, submit, input, keyup, mouseover.
Chamar uma função
Uma expressão em linha serve para uma operação trivial. Assim que a lógica passa de uma linha, escreve uma função:
<script setup>
function addToCart() {
cart.value += 1
}
</script>
<template>
<button class="button" v-on:click="addToCart">Ajouter au panier</button>
</template>Repara no .value dentro do script: estamos a manipular a referência, não o valor desembrulhado. No template, escreve-se sempre {{ cart }} sem .value.
@click="addToCart" passa a própria função: o Vue chama-a com o evento nativo como primeiro argumento. @click="addToCart()" chama-a sem argumento. Aqui, ambas funcionam. O erro clássico surge quando a função espera um valor: @click="updateImage(variant.image)" está correto, mas esquecer os parênteses passaria o evento em vez do caminho da imagem.
O atalho arroba
Tal como o v-bind tem o :, o v-on tem o @:
<button class="button" @click="addToCart">Ajouter au panier</button>É esta a escrita que vais encontrar em toda a documentação e no resto deste tutorial.
Passar um argumento
Vamos fazer a imagem mudar quando o rato passa sobre uma cor. A função recebe o caminho da imagem da variante em causa:
<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 o rato sobre «Rouge»: a imagem fica vermelha. Combinam-se aqui dois mecanismos, o ciclo do capítulo 4 e a ligação de atributo do capítulo 2.
Obter o evento nativo
Sem argumento, a função recebe o evento do DOM. Com argumentos, pede-o explicitamente com $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)
}O objeto recebido é o evento nativo do navegador, sem invólucro: event.target, event.key, event.preventDefault() funcionam como em JavaScript puro.
Os modificadores de evento
O Vue acrescenta sufixos que dispensam o código repetitivo de gestão de eventos:
<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 -->A lista completa, com aquilo que cada modificador substitui:
| Modificador | Equivalente em JavaScript | Uso típico |
|---|---|---|
.prevent | event.preventDefault() | um formulário que não deve recarregar a página |
.stop | event.stopPropagation() | um botão dentro de um cartão clicável: o clique não sobe até ao cartão |
.self | if (event.target !== event.currentTarget) return | fechar uma janela modal com um clique no fundo, não no seu conteúdo |
.once | addEventListener(…, { once: true }) | um botão «Encomendar» que não deve enviar duas vezes |
.capture | addEventListener(…, { capture: true }) | intercetar o evento antes dos filhos |
.passive | addEventListener(…, { passive: true }) | deslocamento e toque no telemóvel, para não bloquear a renderização |
Os modificadores encadeiam-se e leem-se da esquerda para a direita: @click.stop.prevent pára a propagação e só depois anula o comportamento por omissão. Esta ordem conta com o .self: @click.self.prevent só anula o comportamento por omissão dos cliques no próprio elemento, @click.prevent.self anula-o para todos os cliques, filhos incluídos.
O @submit.prevent vai servir no capítulo 10 para impedir o recarregamento da página no envio do formulário.
Modificadores de tecla e de rato
Nos eventos de teclado, um modificador filtra a tecla. O Vue aceita qualquer nome de tecla exposto por KeyboardEvent.key, escrito em kebab-case, mais alguns alias:
<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 -->Os alias disponíveis: .enter, .tab, .delete (Delete e Backspace), .esc, .space, .up, .down, .left, .right. As teclas de sistema .ctrl, .alt, .shift e .meta combinam-se com as outras. E o .exact exige que nenhuma outra tecla de sistema esteja premida:
<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 -->Para o rato, .left, .right e .middle filtram o botão: @click.right.prevent="menuContextuel" substitui o menu do navegador pelo teu.
Vários gestores no mesmo evento
Um evento pode desencadear várias funções, separadas por vírgulas. Nesse caso, cada função é chamada com os parênteses:
<button @click="addToCart(), trackClick('ajout-panier')">Ajouter au panier</button>Para lá de duas chamadas, deixa de ser legível: escreve uma função que chame as outras.
Em resumo
v-on:clickou@click: uma expressão em linha para uma operação trivial, caso contrário uma função.- Sem parênteses, a função recebe o evento nativo; com argumentos, o
$eventpassa-o também. .prevent,.stop,.self,.oncesubstituem o código repetitivo; os modificadores de tecla filtram o teclado; o.exacttranca as combinações.- No script, o estado altera-se com
.value; no template, sem ele.
As funções vivem na opção methods e chegam ao estado através do this: methods: { addToCart() { this.cart += 1 } }. O template, esse, não muda.
Os eventos deste capítulo vêm do DOM. Para que um componente filho avise o seu pai, o Vue tem eventos personalizados com emit: é o tema do capítulo 9, detalhado no guia completo do Vue emit.
Erros frequentes
cart += 1 não faz nada de útil numa referência: escreve cart.value += 1.@click="updateImage" passa o evento nativo em vez do valor esperado. Com um argumento, chama a função: @click="updateImage(variant.image)".$event: @click="faire('bleu', $event)".@click.prevent.self impede o comportamento por omissão de todos os cliques, @click.self.prevent apenas o daqueles cujo alvo é o próprio elemento. A ordem lê-se da esquerda para a direita..passive promete ao navegador que não vai chamar preventDefault(); combinado com .prevent, o navegador ignora um dos dois e mostra um aviso.