Event Handling with v-on
Listening for DOM events with v-on/@, passing arguments, and the event modifiers that replace common boilerplate.
読了時間 2 分
v-on, almost always written with its @ shorthand, attaches an event listener to an element:
<script setup>
import { ref } from "vue";
const count = ref(0);
function increment() {
count.value++;
}
</script>
<template>
<button @click="increment">Count: {{ count }}</button>
</template>For very short handlers, you can write the expression inline instead of defining a named function:
<template>
<button @click="count++">Count: {{ count }}</button>
</template>Both are valid; reach for a named function once the logic is more than a one-liner, so the template stays readable.
Passing arguments, including the event object
<script setup>
function logItem(item, event) {
console.log("Clicked:", item, event.target);
}
</script>
<template>
<button v-for="item in ['a', 'b', 'c']" :key="item" @click="logItem(item, $event)">
{{ item }}
</button>
</template>When you call a method with explicit arguments in the template, Vue no longer passes the native event automatically — use the special $event variable to pass it through yourself when you still need it.
Event modifiers
A huge share of real-world event handlers start with the same boilerplate: calling event.preventDefault() or event.stopPropagation() before doing the actual work. Vue's event modifiers move that boilerplate out of your function and into the template:
<template>
<form @submit.prevent="handleSubmit">
<input type="text" />
<button type="submit">Save</button>
</form>
<div @click="handleOuterClick">
<button @click.stop="handleInnerClick">Inner</button>
</div>
<a href="/docs" @click.once="trackFirstClick">Docs</a>
</template>.preventcallsevent.preventDefault()— here, stopping the form from doing a full-page reload on submit..stopcallsevent.stopPropagation()— the inner click won't also trigger the outer div's handler..oncemakes the listener fire at most one time.
Modifiers can be chained (@click.stop.prevent) and read left-to-right, in the order they apply.
Key modifiers
Keyboard events get the same treatment for common keys:
<template>
<input @keyup.enter="submitSearch" placeholder="Press Enter to search" />
<input @keyup.esc="clearInput" placeholder="Press Esc to clear" />
</template>Without this, you'd write a single generic @keyup handler and manually check event.key === "Enter" inside it. The modifier form says the same thing directly in the template, which is exactly where a reader looking for "what does pressing Enter do here" would look first.
Why this matters beyond convenience: keeping trivial DOM mechanics (prevent default, stop propagation, which key was pressed) out of your handler functions means those functions can focus purely on what should happen — the actual application logic — rather than being cluttered with the plumbing needed to get there.