1. 程式人生 > >$on與$emit實現父子跨多元件通訊

$on與$emit實現父子跨多元件通訊

眾所周知,$on是做事件監聽,$emit是做事件的派發,但對於$dispatch$broadcast大家可能就比較陌生了,這對api是vue1.x版本的,在vue2.x裡已經被廢棄

$on$emit

  • $on對於自身觸發的事件,也是可以監聽的

$dispatch$broadcast

  • $dispatch:用於向上級派發事件,只要是它的父級(一級或多級以上),都可以在元件內通過$on監聽到
  • $broadcast: 用於向下級派發事件,只要是它的子元件,都可以在元件內通過$on監聽到

如何通過$on$emit來實現$dispatch$broadcast,思路大概是,向上遞迴查詢要通訊的元件,或者向下,我們將該功能程式碼提到mixin中,方便各元件複用

    // emitter.js
    const broadcast = function(comName,event,data) {
        this.$children.forEach(p =>{
            if(p.$options.name === comName) {
            p.$emit(event, data) 
            } else{
            broadcast.apply(p,comName,event,data)
            }
        })
        }
    methods: {
        /**
        * comName 目標元件
        * event 事件名
        * data 要傳的資料
        */
        broadcast(comName,event,data) {
        broadcast.call(this, arguments)
        },
        dispatch (comName,event,data) {
            let parent = this.$parent || this.$root;
            let name = parent.$options.name;
            // 這裡是找最接近的父元件
            while (parent && (!name || name !== componentName)) {
            parent = parent.$parent;

            if (parent) {
            name = parent.$options.name;
            }
            }
            if (parent) {
            parent.$emit.apply(parent, [eventName].concat(params));
            }
        },
    }

使用案例

    // 父元件A,省略部分程式碼
    <template>
        <button @click="handleClick">觸發事件</button>
    </template>
    <script>
    import Emitter from '../mixins/emitter.js';
    
    export default {
        name: 'componentA',
        mixins: [ Emitter ],
        methods: {
        handleClick () {
            this.broadcast('componentB', 'sendMsg', 'Hello 我是父元件A');
        }
        }
    }
    </script>
       // 子元件B,省略部分程式碼
    <script>
    import Emitter from '../mixins/emitter.js';
    
    export default {
        name: 'componentB',
        mixins: [ Emitter ],
        // 在created或者mounted做事件監聽
        created () {
            this.$on('sendMsg', this.showMsg)
        },
        methods: {
            showMsg (data) {
                alert(data)
            }
        }
    }
    </script>

和原來的api的區別

  • 需要額外傳入元件的 name 作為第一個引數;
  • 無冒泡機制;
  • 第三個引數傳遞的資料,只能是一個(較多時可以傳入一個物件),而 Vue.js 1.x 可以傳入多個引數,當然,你對 emitter.js 稍作修改,也能支援傳入多個引數,只是一般場景傳入一