Vue.js v2の$emitとイベント修飾子 | 子から親への値の受け渡し方法
Vue.jsの$emitを使って子コンポーネントから親コンポーネントへの値の受け渡し方法をまとめました。
$emitとイベント修飾子の使い方例1
Todoアプリで子のclickイベントを親に渡したいとします。
子コンポーネント
<li>
<button
:class="className"
@click="$emit('complete')"
>
<i class="far fa-circle"></i>{{task.title}}</button>
<button @click="$emit('remove')"><i class="far fa-trash-alt"></i></button>
</li>
$emitでイベントを外に出します。
親コンポーネント
<TaskItem
v-for="(task, index) in tasks" :key="task.id"
:task="task"
@remove="removeTask(index)"
@complete="completeTask(task)"
/>
上のようにして受け取ります。
合わせてクリックイベントが発生したときのメソッドをセットします。
// 一つずつ削除
removeTask(index) {
this.tasks.splice(index, 1)
},
// 完了と未完了をトグル
completeTask(task) {
task.completed = !task.completed
}
$emitとイベント修飾子の使い方例2
モーダルを閉じる操作をしたいとします。
まずは子コンポーネントでカスタムイベントを作成します。
子コンポーネントModal.vue
$emit('close’)とすることでcloseというカスタムイベントを作成できます。
closeを親コンポーネントで使うことができるようになります。
背景部分をクリックしたらモーダルを閉じるようにします。
<template>
<!-- Event Modifierの設定方法
@clickのあとに.selfとするとその要素のみにイベントが適用される -->
<div class="backdrop" @click.self="closeModal">
<div class="modal" :class="{ sale: theme === 'sale'}">
<h1>{{ header }}</h1>
<p>{{ text }}</p>
</div>
</div>
</template>
上の場合、クリックイベントが伝搬して子要素であるh1やpタグでもクリックするとイベントが発火してしまいます。
その場合、.selfといったイベント修飾子(Event Modifier)を使うことで、イベントの伝搬を制御することができます。
イベントの伝搬については、次の記事を参考にしてみてください。
<script>
export default {
// 親から値を受け取るprops
props:['header', 'text', 'theme'],
methods: {
closeModal() {
// emitの中に好きな名前をつけることで親コンポーネントでclickイベントのようなイベントのように使うことができる
this.$emit('close')
}
}
}
</script>
親コンポーネントApp.vue
次のように親コンポーネントでは、closeというオリジナルのイベントが発動したらどうしたいのかを書きます。
<template>
<!-- App.vue root component -->
<h1>{{ title }}</h1>
<div v-if="showModal">
<!-- // 親コンポーネントでは、closeが発動したらどうしたいのかを書く。
今回の場合modalを閉じたいのでtoggleModalを渡す -->
<!-- イベントが伝搬しているので背景をクリックしてもその子要素をクリックしてもmodalが反応するので、Event Modifierを設定する -->
<Modal :header="header" :text="text" theme="sale" @close="toggleModal" />
</div>
<!-- イベント修飾子の設定方法
@clickの後に.rightの形で続ける。
.rightは右クリックしたら、.shiftはshiftキープラスクリックしたら -->
<button @click.shift="toggleModal">Open Modal(shift)</button>
<hr />
<input type="text" ref="name" />
<button @click="handleClick">click me</button>
</template>
イベント修飾子には、いろいろあります。
クリックに.rightというイベント修飾子をつけると右クリックしたら、発火します。
.shiftをつけるとshiftキーを押しながらクリックしたらイベントが発火するようになります。
詳しくはVueの公式ドキュメントを参考にしましょう。
<script>
import Modal from './components/Modal';
export default {
name: 'App',
components: { Modal },
data() {
return {
title: 'My First Vue App',
header: 'ヘッダー部分',
text: 'ここにテキスト',
showModal: false
};
},
methods: {
handleClick(e) {
console.log(this.$refs.name); //ref="name"の入っているが出力される
this.$refs.name.classList.add('active'); //activeクラスを付与する
this.$refs.name.focus(); //clickしたらref="name"にfocusする
},
toggleModal() {
this.showModal = !this.showModal;
}
}
};
</script>