Vue组件间通信事件总线和消息订阅与发布

275 阅读2分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

事件总线

父组件->子组件:使用props。

子组件->父组件:使用$emit。

事件总线可以用在任意组件之间传值。

事件总线就是在接收数据的组件接收绑定事件的回调,在发送数据的组件触发事件并带值。其中借助了一个中间属性,把事件放在中间属性上面。

中间属性的特点:

1.全部组件都能看见。

2.能调用onon、off、$emit,对事件进行操作。

为了满足以上两点,需要操作Vue的原型对象,修改main.js文件:

安装全局总线事件:

main.js

...

new Vue({
  ...
  beforeCreate() {
    Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
  },
  ...
}).$mount('#app')

接收数据的组件监听事件:

oneComponent.vue

<template>
  <div>
    <span>这是组件A,接收B组件传值。{{ myData }}</span>
  </div>
</template>

<script>
export default {
  name: "oneComponent",
  data() {
    return {
      myData: {},
    };
  },
  methods: {
    listOne(data) {
      this.myData = data;
      console.log(data);
    },
  },
  mounted() {
    // 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
    // this.$bus.$on("事件名", 事件回调);
    this.$bus.$on("eventName", this.listOne);
  },
  // 当组件销毁时,最好解绑用到的事件。
  beforeDestroy() {
    this.$bus.$off("eventName");
  },
};
</script>

<style  lang="less">
</style>

在接收时,也可以使用箭头函数去接收:

...
mounted() {
    // 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
    // this.$bus.$on("事件名", 事件回调);
    this.$bus.$on("eventName", (data) => {
      this.myData = data;
      console.log(data);
    });
  },
...

发送数据的组件触发事件:

twoComponent.vue

<template>
  <div>
    这是组件B
    <button type="primary" @click="updateData">给组件A传值</button>
  </div>
</template>

<script>
export default {
  name: "twoComponent",
  data() {
    return {
      list: {
        value: "value1",
        type: "type1",
      },
    };
  },
  methods: {
    updateData() {
      // 触发事件,并传值
      this.$bus.$emit("eventName", this.list);
    }
  },
};
</script>

<style  lang="less">
</style>

组件使用:

<template>
  <div>
    <one-component></one-component>
    <span>----------------</span>
    <two-component></two-component>
  </div>
</template>

<script>
import oneComponent from '@/components/oneComponent'
import twoComponent from '@/components/twoComponent'
export default {
    ...
    components: { oneComponent,twoComponent },
    ...
}
</script>

<style  lang="less">
</style>

注意:刚开始理解成了,可以先在B页面触发即$emit,再切换A页面看是否收到了数据($on是放在mounted里面的)。这样只有切换到A页面,才能调用$on,所以这一流程的执行顺序为先$bus.$emit,再$bus.$on。这样一直没有收到数据,这个理解是错误的。

触发后再绑定事件自然就不会接收已结束的事件了,$on就监听不到触发的事件,所以需要现有$on的存在,才能接收$emit触发事件所传过去的值。

事件应该是先注册($on)而后才能去触发($emit)。

监听事件时,只要有组件触发事件就能接收到数据。

接收数据的注册事件,事件的回调留在该组件,发送数据的组件触发事件,传递数据。

消息订阅与发布

消息订阅与发布也是实现组件间任意通信的方法。

先订阅(接收数据的订阅)-再发布(发送数据的发布)

这里需要安装库,有很多种,这里使用pubsub-js

先安装库:

npm install pubsub-js

在使用的组件中引入,引入的是一个对象,里面有很多方法。

接收消息的组件订阅消息:

oneComponent.vue

<template>
  <div>
    <span>这是组件A,接收B组件传值。{{ myData }}</span>
  </div>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
  name: "oneComponent",
  data() {
    return {
      myData: {},
    };
  },
  methods: {

  },
  mounted() {
    // 订阅消息,只要有组件发布消息,就能接收到数据。
    this.pubId = pubsub.subscribe("msgName", (msgName,data) => {
      this.myData = data;
      console.log(msgName);
      console.log(data);
    });
  },
  // 当组件销毁时,取消订阅。
  beforeDestroy() {
    pubsub.unsubscribe(this.pubId);
  },
};
</script>

<style  lang="less">
</style>

发送消息的组件发布消息:

twoComponent.vue

<template>
  <div>
    这是组件B
    <button type="primary" @click="updateData">给组件A传值</button>
  </div>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
  name: "twoComponent",
  data() {
    return {
      list: {
        value: "value1",
        type: "type1",
      },
    };
  },
  methods: {
    updateData() {
      // 发布消息
      pubsub.publish("msgName", this.list);
    }
  },
};
</script>

<style  lang="less">
</style>