Event Handling - イベント処理と modifier
ロードマップ: Vue.js学習ロードマップ
公式ドキュメント: https://vuejs.org/guide/essentials/event-handling.html
What(何についてか)
Vue の v-on(省略形 @)を使って DOM イベントを受け取り、状態更新や関数呼び出しを行うための仕組みを扱う。
この章では、inline handler と method handler の使い分け、DOM Event の自動受け渡し、$event の明示的な受け渡し、event modifier・key modifier・mouse button modifier の役割を整理する。
Why(なぜ必要か)
Vue の UI はリアクティブな状態に応じて更新されるが、状態変化の入口はユーザー操作である。 クリック、フォーム送信、キーボード入力、スクロールなどのイベントを適切に受け取り、DOM 都合の制御と業務ロジックを分離することで、テンプレートと処理の見通しを良くできる。
How(どう動くか)
1. v-on / @ でイベントを監視する
<button @click="count++">Add 1</button>@click は click イベント発生時に右辺の式や関数を実行する。
Vue 独自のイベントというより、DOM イベントをテンプレートから宣言的に扱いやすくしたものとして理解する。
2. handler の書き方は inline と method の2系統がある
Inline handler
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>
</template>短い式をその場で実行する。 単純なカウンタ更新やフラグ切り替えのように、テンプレート上で意味が完結する処理に向く。
Method handler
<script setup>
import { ref } from 'vue'
const name = ref('Vue.js')
function greet(event) {
alert(`Hello ${name.value}!`)
if (event) {
alert(event.target.tagName)
}
}
</script>
<template>
<button @click="greet">Greet</button>
</template>複雑な処理は関数へ分離する。
@click="greet" のように関数参照を渡すと、Vue は native DOM Event を第1引数として自動で渡す。
3. greet と greet() は別物である
@click="greet"は method handler@click="greet()"は inline handler
Vue は foo や foo.bar のような識別子・プロパティ参照を method handler とみなし、foo() や count++ のような式は inline handler とみなす。
そのため、@click="greet()" では event は自動注入されない。
必要であれば $event を明示する。
<button @click="greet($event)">Greet</button>
<button @click="greet('hello', $event)">Greet</button>4. $event で元の DOM Event を明示的に受け取れる
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>inline handler で独自引数と event を併用したいときに使う。 実務では「削除対象の id と event を両方渡す」などの場面で有効である。
5. event modifier で DOM イベント制御をテンプレートへ寄せる
<form @submit.prevent="onSubmit"></form>
<a @click.stop="doThis"></a>
<div @click.self="closeModal">...</div>handler 内で preventDefault() や stopPropagation() を都度書かず、テンプレート側に制御意図を明示できる。
主な event modifier
| Modifier | 役割 | 実務例 |
|---|---|---|
.stop | 親要素への伝播を止める | カード内の削除ボタン |
.prevent | ブラウザ標準動作を止める | フォーム送信, リンク遷移抑止 |
.self | event.target がその要素自身のときだけ実行する | モーダル背景クリックで閉じる |
.capture | capture phase で先に拾う | 特殊なイベント順制御 |
.once | 一度だけ発火する | 初回のみの導線 |
.passive | prevent しない前提でブラウザ最適化を有効にする | scroll / touch 系 |
modifier の順序は意味を持つ
@click.prevent.self="doThat" と @click.self.prevent="doThat" は同じではない。
Vue は modifier を書いた順に対応コードを組み立てるため、条件判定より前に preventDefault() を実行するか、後に実行するかが変わる。
概念的には次の違いになる。
// @click.prevent.self="doThat"
event.preventDefault()
if (event.target !== event.currentTarget) return
doThat()// @click.self.prevent="doThat"
if (event.target !== event.currentTarget) return
event.preventDefault()
doThat()前者は子要素クリックでも default action を止める可能性があり、後者はその要素自身がクリックされた場合にだけ default action を止める。
.passive と .prevent は併用しない
.passive は「この listener は preventDefault() しない」とブラウザへ伝えるため、.prevent と思想が衝突する。
スクロール系イベントの性能改善では .passive 単体で使う。
6. key modifier で特定のキーだけ反応させる
<input @keyup.enter="submit" />
<input @keyup.page-down="onPageDown" />Vue は KeyboardEvent.key に応じた key modifier を提供する。
よく使う alias として .enter, .tab, .delete, .esc, .space, .up, .down, .left, .right がある。
System modifier keys
<input @keyup.alt.enter="clear" />
<div @click.ctrl="doSomething">Do something</div>.ctrl, .alt, .shift, .meta を組み合わせて補助キー付き操作を定義できる。
.exact を使うと、余計な補助キーなしの厳密な組み合わせだけに限定できる。
<button @click.ctrl.exact="onCtrlClick">A</button>
<button @click.exact="onClick">A</button>IME を考慮する場合は handler 側で補う
日本語入力のように IME 変換中の Enter と送信確定の Enter を区別したい場合、@keyup.enter や @keydown.enter だけでは不十分なことがある。
その場合は event.isComposing や composition 系イベントを使って判定する。
function onEnter(event: KeyboardEvent) {
if (event.isComposing) return
submit()
}7. mouse button modifier でボタン種別を限定する
.left.right.middle
これらは物理的な左右ボタンではなく、論理的な main / secondary / auxiliary 操作に対応する。
右クリック独自メニューでは contextmenu と .prevent を組み合わせる設計も多い。
<div @contextmenu.prevent="openMenu">
Right click me
</div>イベント処理の全体フロー
flowchart LR A["ユーザー操作"] --> B["DOM Event 発生"] B --> C["Vue template の @event が受け取る"] C --> D["modifier で制御"] D --> E["handler 実行"] E --> F["状態更新"] F --> G["UI 再描画"]
実務での書き分け指針
単純な状態更新
<button @click="count++">Add 1</button>複雑な処理
<button @click="save">Save</button>業務引数を渡したい
<button @click="removeItem(id)">Delete</button>業務引数と event を両方使いたい
<button @click="removeItem(id, $event)">Delete</button>フォーム送信でページリロードを止めたい
<form @submit.prevent="onSubmit">モーダル背景クリックだけで閉じたい
<div @click.self="closeModal">Options API → Composition API 差分(補足)
| 項目 | Options API(旧) | Composition API(新) |
|---|---|---|
| handler の定義場所 | methods に配置する | <script setup> で通常の関数として定義する |
| 状態参照 | this.count, this.name を使う | ref / reactive を直接参照する |
this の依存 | this に現在インスタンスが束縛される | this を使わず、変数と関数を直接扱う |
| イベント処理の書き味 | 構造は似るが methods 中心 | setup 由来の関数と状態をそのままテンプレートへ公開する |
Key Concepts
| 用語 | 説明 |
|---|---|
v-on / @ | DOM イベントを監視するディレクティブ |
| inline handler | テンプレート上で式を直接実行する handler |
| method handler | 関数参照を渡して呼び出す handler |
$event | inline handler 内で参照できる元の DOM Event |
| event modifier | 伝播や default action などのイベント制御を宣言する記法 |
| key modifier | 特定キーや補助キーに限定する記法 |
.exact | 補助キーの厳密一致を要求する modifier |
| mouse button modifier | 主ボタン / 副ボタン / 補助ボタンに応じて分岐する記法 |
event.isComposing | IME 変換中かどうかを判定する DOM Event のプロパティ |