仮に親画面をメイン画面、子画面を編集画面として子画面で編集した結果を親画面に返すような処理を例に説明する。
親(呼び出し元)コンポーネント
Parent.vue
<template> <div> <!-- iroiro --> <p>{{ parentData }}</p> <child-component :data="parentData" v-on:onUpdate="onUpdate"></child-component> </div> </template> <script lang="ts"> import Vue from "vue" import ChildComponent from "./Child.vue" export default Vue.extend({ components: { ChildComponent, }, data() { return { parentData: 0, } }, methods: { onUpdate(data: number) { this.parentData = data }, }, }) </script>
<child-component :data="parentData" v-on:onUpdate="onUpdate"></child-component>が重要
v-on:onUpdate="onUpdate" で子コンポーネントに親の関数(onUpdate)を伝えている。
子コンポーネント
Child.vue
<template> <div> <!-- iroiro --> <button @click="handleClick">更新</button> </div> </template> <script lang="ts"> import Vue from "vue" /** * 呼び出し元でonUpdate(data: number) を実装すること * @example * <child-component :data="parentData" v-on:onUpdate="onUpdate"></child-component> */ export default Vue.extend({ props: { data: String, }, data() { return { updateData: 1, } }, methods: { /** 親コンポーネントのonUpdate呼び出し */ handleClick() { if (this.$listeners["onUpdate"]) { this.$emit("onUpdate", this.updateData) } else { console.log("呼び出し側でonUpdateが実装されていません") // tslint:disable-next-line:no-debugger debugger } }, }, }) </script>
ボタンを押すとhandleClick()が呼ばれ親のonUpdateが走り0が1になる。
以上でよく見る実装形式に落とし込める。
Childコンポーネントを使用したい場合は呼び出し元でonUpdate(data: number)を実装するだけでいい。
関数名は文字列でしか指定できないのでインテリセンスが効かない。
後々を考えると子コンポーネントに使用方法をコメントしておくような工夫が必要になるかと。
親の値を直接書き換えることもできるようだがやるべきではないだろう。
v-on:xxxxについてはthis.$listenersに連想配列形式で格納されているようなのでこれを参照すれば実装されているか確認できる。
v-on:onUpdate1="onUpdate" などにするとhandleClickはelse句の処理が走る。
親のメソッドは引数さえ同じなら v-on:onUpdate="onComplete" のように名前を変えても問題ない。
参考
http://www.webopixel.net/javascript/1224.html
https://jp.vuejs.org/v2/guide/components.html
https://jp.vuejs.org/v2/api/#vm-listeners
Vueで親から子へ値(変数)の受け渡し(TypeScript)