vue-routerで親子間でのイベント処理

カテゴリー
JavaScript Laravel Vue

概要

vue-router使用時の「子→親」あるいは「子1→子2」のイベント渡しの記述方法について自分用メモ

:warning:ソースコードは簡略化したもので、ちゃんとテストしていないので動かないかも

サンプルコード

this.$router.app.$on を扱うのがポイント。
それ以外は通常のイベントバスのやり方と同じ。

主要な部分 ( app.js )

//(前略)
const app = new Vue({
    router, // これが「ルーターインスタンスを root インスタンスに router オプションとして」かな?
    el: '#app',
    render: h => h(App)
});

親コンポーネント ( parent.js )

<template>
    <div>
        <child1></child1>
        <child2></child2>
    </div>
</template>
<script>
// 子2つを配置するのみ
import component_child1 from './child1.vue'
import component_child2 from './child2.vue'
export default {
    components: {
      'child1': component_child1,
      'child2': component_child2
    }
};
</script>

子コンポーネント(child1.vue, child2.vueの2つ)

目標とする動作は下記。

  1. child1でボタンを押すと test_method_child1 が実行される。
  2. test_method_child1 内で test_event_global がスローされ、child1は非表示。
  3. child2でイベントの解除(重要、後述。参考資料を参照。)
  4. child2ではイベントを test_event_globaltest_event_child2 としておく。
  5. child2でイベントを受け取ったら、v-on:test_event_child2test_method_child2 が実行。
  6. child2が表示され、Hello Worldが見える。
<template>    <div v-show="visible_child1">       <button v-on:click="test_method_child1">Run Test</button>    </div></template><script>export default {
    data() {
        return {
            visible_child1 : true  // 表示/非表示制御
        };
    },
    methods: {
        test_method_child1() {
            this.visible_child1 = false;
            // イベントバスを this.$router.app として、イベントをスロー
            this.$router.app.$emit('test_event_global');
        }
    }
}
</script>
<template>    <div v-on:test_event_child2="test_method_child2" v-show="visible_child2">       Hello world !!
    </div></template><script>export default {
    data() {
        return {
            visible_child2 : false // 表示/非表示制御
        };
    },
    mounted() {
        // イベントバスを this.$router.app として、コンポーネントのイベントに紐づけている
        this.$router.app.$off('test_event_global');
        this.$router.app.$on('test_event_global', this.test_event_child2);
    },
    methods: {
        test_method_child2() {
            this.visible_child2 = true;
        }
    }
}
</script>

注意点

解除が行われない、というより .$off をしないと蓄積するようです

ページ遷移して created や mounted が何度も呼ばれると、そのたびに蓄積されてしまうらしい。
( beforeDestroy か destroyed の中で解除すればいいのかな )


上記は例。$onでメソッドを直接叩くこともできるはず。
表示/非表示みたいなことを実現するだけならv-onは取ってしまって、child2.vue で、

<div v-show="visible_child2">
(中略)
this.$router.app.$on('test_event_global', this.test_method_child2);

とすることも。

参考資料

  1. Vue Router / API リファレンス
  2. Vue.js のグローバルイベントバスでの親子間以外の通信と vue-router