$on and $emit realize parent-child cross component communication

Keywords: Front-end Vue

As we all know, $on is for event monitoring, and $emit is for event distribution. But you may be unfamiliar with $dispatch and $broadcast. This api is version 1. X of vue1.x, which has been abandoned in vue2.x

$on and $emit

  • $on can also monitor events triggered by itself

$dispatch and $broadcast

  • $dispatch: used to dispatch events to the superior. As long as it is the parent (one or more levels), it can be monitored through $on in the component
  • $broadcast: used to distribute events to lower level. As long as it is a sub component, it can be monitored through $on in the component

How to realize $dispatch and $broadcast through $on and $emit? The idea is to recursively search the components to be communicated up, or down. We will refer this function code to mixin to facilitate the reuse of each component

    // 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 Target component
        * event Event name
        * data Data to be transmitted
        */
        broadcast(comName,event,data) {
        broadcast.call(this, arguments)
        },
        dispatch (comName,event,data) {
            let parent = this.$parent || this.$root;
            let name = parent.$options.name;
            // Here is to find the closest parent component
            while (parent && (!name || name !== componentName)) {
            parent = parent.$parent;

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

Use cases

    // Parent component A, omitting some code
    <template>
        <button @click="handleClick">Trigger event</button>
    </template>
    <script>
    import Emitter from '../mixins/emitter.js';
    
    export default {
        name: 'componentA',
        mixins: [ Emitter ],
        methods: {
        handleClick () {
            this.broadcast('componentB', 'sendMsg', 'Hello I am the parent component A');
        }
        }
    }
    </script>
       // Sub component B, omitting some codes
    <script>
    import Emitter from '../mixins/emitter.js';
    
    export default {
        name: 'componentB',
        mixins: [ Emitter ],
        // Do event monitoring in created or mounted
        created () {
            this.$on('sendMsg', this.showMsg)
        },
        methods: {
            showMsg (data) {
                alert(data)
            }
        }
    }
    </script>

Differences from the original api

  • The name of the additional incoming component is required as the first parameter;
  • No bubbling mechanism;
  • The data passed by the third parameter can only be one (one object can be passed in when there are many), while Vue.js 1.x can pass in multiple parameters. Of course, you can modify twitter.js a little and also support passing in multiple parameters, but an object passed in by a general scenario is enough

Posted by xcali on Sun, 10 Nov 2019 09:22:05 -0800