vue2 跨多层组件通信——可使用 dispatch 和 broadcast

简介

Element dispatch 和 broadcast 都是 JavaScript 中的事件相关概念,但它们有些不同:
Element dispatch 是用于在特定的 HTML 元素上分派(即发起)自定义事件的过程。只有特定的元素会收到这些事件。
Broadcast 是一种在整个页面(或文档)上广播事件并在其所有子元素中调用处理程序的方式。在这种情况下,父元素会将事件传递给其子元素,直到找到一个可以处理该事件的元素。
在 Element dispatch 中,事件只会被处理它所分派到的元素。而 Broadcast 则会在所有子元素中调用处理程序,所以在一个具有多层嵌套元素的页面上,可能会有多个元素响应同一个 broadcast 事件。

最近在使用zfs-ui组件(改写element)过程中发现组件通信大量使用 dispatch 和 broadcast 两个方法,来看看如何实现的这两个函数。

代码部分:

emitter.js

function broadcast(componentName, eventName, params) {
  this.$children.forEach((child) => {
    const name = child.$options.componentName;

    if (name === componentName) {
      child.$emit(...[eventName].concat(params));
    } else {
      broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}
export default {
  methods: {
    dispatch(componentName, eventName, params) {
      let parent = this.$parent || this.$root;
      let name = parent.$options.componentName;

      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit(...[eventName].concat(params));
      }
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params);
    },
  },
};

在这里插入图片描述

代码分析:

dispatch 和 broadcast 方法都需要 3 个参数:

  1. componentName 组件名称;
  2. eventName 事件名称;
  3. params 传递的参数。

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

使用方式

兄弟组件之间的通信可以很好的诠释上述两个事件。假设父组件 App.vue 中引入了两个子组件 Hello.vue 和 Fuck.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.vue 与 Hello.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 组件通信方式总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值