Vue — v-on / @ (イベント)
テクノロジ系 / L01 template-syntax — テンプレート構文
Vue — v-on / @ (イベント)
基本
<script setup>
const count = ref(0);
function increment() { count.value++; }
</script>
<template>
<button @click="increment">+</button>
<button @click="count++">+</button> <!-- インライン -->
<button @click="count = count - 1">-</button>
<button @click="handle($event, count)">handle</button> <!-- 引数渡し -->
</template>@event で各種イベント。
ref / count.value は L03 ch01。
イベント Modifier
<template> <!-- .prevent: event.preventDefault() --> <form @submit.prevent="onSubmit">...</form> <!-- .stop: event.stopPropagation() --> <div @click="outer"><button @click.stop="inner">Btn</button></div> <!-- .once: 1回だけ --> <button @click.once="init">Initialize</button> <!-- .self: 自分自身で発火したときだけ --> <div @click.self="closeModal">背景</div> </template>
JS で e.preventDefault() を書く代わりに .prevent で済む。
Key Modifier
<template>
<input
@keydown.enter="submit"
@keydown.esc="cancel"
@keydown.ctrl.s="save"
/>
</template>主要キー: enter, tab, delete, esc, space, up, down, left, right
修飾: .ctrl, .alt, .shift, .meta, .exact
@keydown.ctrl.s で「Ctrl+S」を捕捉。
Mouse Modifier
<template> <button @click.left="leftClick">Left</button> <button @click.right="rightClick">Right</button> <button @click.middle="middleClick">Middle</button> </template>
ハンドラに引数
<template>
<button v-for="item in items" :key="item.id"
@click="deleteItem(item.id)">
Delete
</button>
</template>呼び出し式 deleteItem(item.id) の形で書ける。
イベントオブジェクトと両方欲しいなら:
<button @click="handleClick($event, item.id)">Delete</button>
$event で event object。
TypeScript で型付け
<script setup lang="ts">
function handleInput(e: Event) {
const target = e.target as HTMLInputElement;
console.log(target.value);
}
</script>
<template>
<input @input="handleInput" />
</template>inline で書くなら ($event as any) か as キャストが必要。
ハンドラ関数に切り出す方が型がきれい。
まとめ
@event="..."でイベント (v-on:の短縮)- modifier で
preventDefault / stopPropagation / once等が書ける - key modifier で
Enter / Esc / Ctrl+S等を捕捉 - 引数あり呼び出しも書ける
$eventで event object 参照- TS では関数に切り出して型を付ける
次は v-if / v-show。
考えてみよう
既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。
Lv1: 基本 — イベントハンドラ
問題
<script setup>
const count = ref(0);
const text = ref("");
function increment() { count.value++; }
function reset() { count.value = 0; }
function handle(e: KeyboardEvent) {
console.log(e.key);
}
</script>
<template>
<p>{{ count }}</p>
<button @click="increment">+</button>
<button @click="count++">+ inline</button>
<button @click="reset">reset</button>
<input v-model="text" @keydown="handle" />
</template>合格基準
- 4イベント全部動く
- インライン式と関数の両方OK
Lv2: 応用 — Modifier
問題
<template>
<form @submit.prevent="onSubmit">
<input @keydown.enter="onEnter" />
<input @keydown.ctrl.s="onSave" />
<input @keydown.esc="onCancel" />
<button>Submit</button>
</form>
<div @click="outer">
<button @click.stop="inner">inner (stopPropagation)</button>
</div>
<button @click.once="initOnce">Init (1回だけ)</button>
</template>各 modifier の効果を観察。
合格基準
- .prevent でリロード止まる
- .stop で親の click 走らない
- .once で1回しか発火しない
- .enter / .ctrl.s / .esc が動く
Lv3: 発展 — TS で型付き event handler
問題
<script setup lang="ts">
function handleInput(e: Event) {
const target = e.target as HTMLInputElement;
console.log(target.value);
}
function handleSubmit(e: SubmitEvent) {
e.preventDefault();
const form = e.target as HTMLFormElement;
const data = new FormData(form);
console.log(Object.fromEntries(data));
}
</script>
<template>
<form @submit="handleSubmit">
<input name="name" @input="handleInput" />
<button>Submit</button>
</form>
</template>合格基準
- TS で event 引数に型
- form data 取得
提出
submission.md に3問の回答を。