コンポーネントのイベント
このページは、すでにコンポーネントの基礎を読んでいることを前提にしています。初めてコンポーネントに触れる方は、まずそちらをお読みください。
イベントの発行と購読
コンポーネントは、組み込みの $emit
メソッドを使用して、テンプレート式(例: v-on
ハンドラー内)で直接カスタムイベントを発行できます:
template
<!-- MyComponent -->
<button @click="$emit('someEvent')">Click Me</button>
そして、親コンポーネントは v-on
を使ってイベントを購読できます:
template
<MyComponent @some-event="callback" />
.once
修飾子は、コンポーネントのイベントリスナーでもサポートされています:
template
<MyComponent @some-event.once="callback" />
コンポーネントや props と同様に、イベント名も自動的な大文字・小文字の変換を提供します。キャメルケースのイベントを発行しましたが、親ではケバブケースのリスナーを使用して購読できることに注意してください。props 名の大文字・小文字の使い分けと同様に、テンプレートではケバブケースのイベントリスナーを使用することをお勧めします。
TIP
ネイティブの DOM イベントとは異なり、コンポーネントから発行されたイベントはバブリングしません。直接の子コンポーネントから発行されたイベントのみを購読できます。兄弟コンポーネントや深くネストしたコンポーネント間で通信する必要がある場合は、外部のイベントバスやグローバルな状態管理ソリューションを使ってください。
イベントの引数
イベントで特定の値を発行すると便利な場合があります。例えば、 <BlogPost>
コンポーネントに、テキストをどれだけ拡大するかを担当させたい場合があります。そのような場合、$emit
に追加の引数を渡して値を提供できます:
template
<button @click="$emit('increaseBy', 1)">
Increase by 1
</button>
次に、親でイベントを購読する際に、リスナーとしてインラインのアロー関数を使用することで、イベントの引数にアクセスできます:
template
<MyButton @increase-by="(n) => count += n" />
または、イベントハンドラーがメソッドの場合は:
template
<MyButton @increase-by="increaseCount" />
その値はそのメソッドの最初のパラメーターとして渡されます:
js
function increaseCount(n) {
count.value += n
}
TIP
$emit()
に渡されたイベント名の後にあるすべての追加の引数はリスナーに転送されます。たとえば $emit('foo', 1, 2, 3)
とすると、リスナー関数は 3 つの引数を受け取ります。
発行するイベントの宣言
defineEmits()
マクロ を使用して、コンポーネントが発行するイベントを明示的に宣言できます:
vue
<script setup>
defineEmits(['inFocus', 'submit'])
</script>
<template>
で使用した $emit
メソッドは、コンポーネントの <script setup>
セクション内ではアクセスできませんが、代わりに defineEmits()
が同等の関数を返してくれるので、それを使用できます:
vue
<script setup>
const emit = defineEmits(['inFocus', 'submit'])
function buttonClick() {
emit('submit')
}
</script>
defineEmits()
マクロは関数の中では使用できません。上記の例のように、<script setup>
内に直接記述する必要があります。
<script setup>
の代わりに明示的な setup
関数を使う場合は、イベントは emits
オプションを使って宣言する必要があり、emit
関数は setup()
コンテキスト上で公開されます:
js
export default {
emits: ['inFocus', 'submit'],
setup(props, ctx) {
ctx.emit('submit')
}
}
setup()
コンテキストの他のプロパティと同様に、emit
は安全に分割代入できます:
js
export default {
emits: ['inFocus', 'submit'],
setup(props, { emit }) {
emit('submit')
}
}
emits
オプションと defineEmits()
マクロはオブジェクト構文もサポートしています。TypeScript を使用している場合は引数の型付けができ、発行されるイベントのペイロードのランタイムバリデーションを実行できます:
vue
<script setup lang="ts">
const emit = defineEmits({
submit(payload: { email: string, password: string }) {
// バリデーションの合格/不合格を示すための
// `true` または `false` を返す
}
})
</script>
<script setup>
で TypeScript 使用している場合、純粋な型アノテーションを使用して、発行するイベントを宣言することもできます:
vue
<script setup lang="ts">
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
</script>
任意ですが、コンポーネントがどのように動作すべきかをよりよく文書化するために、発行されるすべてのイベントを定義することが推奨されます。また、これにより Vue は既知のリスナーをフォールスルー属性から除外し、サードパーティのコードによって手動でディスパッチされた DOM イベントによって起こるエッジケースを回避できます。
TIP
ネイティブイベント(例: click
)が emits
オプションに定義されている場合、リスナーはコンポーネントが発行する click
イベントのみを購読し、ネイティブの click
イベントには反応しなくなります。
イベントのバリデーション
発行するイベントは、props の型バリデーションと同様に、配列構文ではなくオブジェクト構文で定義されている場合にバリデーションできます。
バリデーションを追加するには、「emit
の呼び出しに渡された引数」を受け取り、「イベントが正当かどうかを示す真偽値」を返す関数をイベントに割り当てます。
vue
<script setup>
const emit = defineEmits({
// バリデーションなし
click: null,
// submit イベントをバリデーション
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
</script>