vue2组件通信-使用dispatch和broadcast

6,161 阅读1分钟
原文链接: lz5z.com

最近在使用 Element 过程中发现组件通信大量使用 dispatchbroadcast 两个方法,之前在 vue2 组件通信 也提到过 vue2 中取消了 $dispatch$broadcast 两个重要的事件,而 Element 重新实现了这两个函数。

代码地址放在 element-ui/lib/mixins/emitter

emitter.js

"use strict";
exports.__esModule = true;
function _broadcast(componentName, eventName, params) {
  this.$children.forEach(function (child) {
    var name = child.$options.componentName;
    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      _broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}
exports.default = {
  methods: {
    dispatch: function dispatch(componentName, eventName, params) {
      var parent = this.$parent || this.$root;
      var name = parent.$options.componentName;
      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;
        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    broadcast: function broadcast(componentName, eventName, params) {
      _broadcast.call(this, componentName, eventName, params);
    }
  }
};

解析

dispatchbroadcast 方法都需要 3 个参数,componentName 组件名称, eventName 事件名称, params 传递的参数。

dispatch 方法会寻找所有的父组件,直到找到名称为 componentName 的组件,调用其 $emit() 事件。broadcast 方法则是遍历当前组件的所有子组件,找到名称为 componentName 的子组件,然后调用其 $emit() 事件。

这里也看出了 Element 中的 dispatchbroadcast 的不同,vue1 中的 $dispatch$broadcast 会将事件通知给所有的 父/子 组件,只要其监听了相关事件,都能够(能够,不是一定)触发;而 Element 则更像是定向爆破,指哪打哪,其实更符合我们日常的需求。

使用方式

兄弟组件之间的通信可以很好的诠释上述两个事件。假设父组件 App.vue 中引入了两个子组件 Hello.vueFuck.vue
如果你的项目中巧合使用了 Element,那可以按照下面的方式将其引入进来,如果没有用 Element 也不用担心,复制上面的 emitter.js,通过 mixins 的方式引入即可。

App.vue 中监听 message 事件,收到事件后,通过 broadcast 和接收到的参数,将事件定向传播给相关组件。

<template>
  <div id="app">
    <hello></hello>
    <fuck></fuck>
  </div>
</template>
<script>
  import Hello from 'components/Hello'
  import Fuck from 'components/Fuck'
  import Emitter from 'element-ui/lib/mixins/emitter'
  export default {
    name: 'app',
    componentName: 'ROOT',
    mixins: [Emitter],
    components: {
      Hello,
      Fuck
    },
    created () {
      this.$on('message', params => {
        this.broadcast(params.componentName, params.eventName, params.text)
      })
    }
  }
</script>

Fuck.vueHello.vue 的内容基本相同,下面只列出 Fuck.vue

import Emitter from 'element-ui/lib/mixins/emitter'
import event from 'mixins/event'
export default {
  componentName: 'Fuck',
  mixins: [Emitter, event],
  data () {
    return {
      name: 'Fuck',
      textarea: '',
      tableData: []
    }
  },
  methods: {
    submit () {
      this.communicate('message', {
        componentName: 'Hello',
        text: this.textarea
      })
      this.textarea = ''
    }
  },
  created () {
    this.$on('message', text => {
      this.tableData.push(this.getMessage(text))
    })
  }
}

mixins/event.js

import Emitter from 'element-ui/lib/mixins/emitter'
export default {
  mixins: [Emitter],
  methods: {
    communicate (event, params = {}) {
      this.dispatch('ROOT', event, Object.assign({
        eventName: event
      }, params))
    }
  }
}

Fuck.vue 中监听了 message 事件,当收到消息时,向 tableData 中加入新的值。而 summit 方法则调用 event.js 中的 communicate 方法,通过 dispatch 方法将事件传播给 ROOT 组件。

完整代码地址

vue 组件通信方式总结

  1. 父组件向子组件传递信息使用 props down
  2. 子组件向父组件传递信息使用 event up
  3. 其它关系类型组件通信使用 global event bus
  4. 大型 SPA 组件之间通信使用 Vuex 管理组件状态
  5. 使用 Element 下 emitter.js 中的 dispatch 和 broadcast 做事件定向传播