Vue3中采用EventBus方式进行组件间通信与Vue2有一定区别
1.创建EventBus
在Vue2中,我们可以在main.js中创建一个全局的EventBus,代码如下:
// EventBus.js
import Vue from 'vue'
const EventBus = new Vue()
export default EventBus// main.js
import EventBus from './EventBus'
Vue.prototype.$bus = EventBus
在Vue3中,我们需要使用createApp来创建Vue实例,并使用provide和inject来创建全局的EventBus,代码如下:
// EventBus.js
import { createApp } from 'vue'
const app = createApp({})
const EventBus = app.provide('EventBus', new app())
export default EventBus// main.js
import EventBus from './EventBus'
createApp(App).use(EventBus).mount('#app')-----------------
// 在 main.js 或入口文件中
import { createApp, provide } from 'vue';
import App from './App.vue';const app = createApp(App);
const eventBus = createApp({});// 将 eventBus 实例作为提供者提供给子组件
app.provide('eventBus', eventBus);app.mount('#app');
2.使用EventBus进行通信
在Vue2中,我们可以通过$emit和$on方法来进行通信,代码如下:
// 发送通信
this.$emit('event', data)// 接收通信
this.$on('event', (data) => {console.log(data)
})// 销毁
this.$off('event')
在Vue3中,我们可以通过$emit和$on方法来进行通信,但是需要在组件中使用AppContext来获取EventBus,代码如下:
// 发送通信
const app = getCurrentInstance().appContext.app
app.config.globalProperties.$EventBus.emit('event', data)// 接收通信
const app = getCurrentInstance().appContext.app
app.config.globalProperties.$EventBus.on('event', (data) => {console.log(data)
})// 销毁
const app = getCurrentInstance().appContext.app
app.config.globalProperties.$EventBus.off('event')-------------------
import { inject } from 'vue';export default {// ...created() {const eventBus = inject('eventBus');// 使用 eventBus 进行事件的发布和订阅},// ...
}
总的来说,Vue3与Vue2在EventBus方式上的区别不大,只是在创建全局EventBus的方式上有所不同,但是使用起来差异较大,需要根据实际情况进行选择。
封装EventBus.js
类方式
class Event {constructor() {this.queue = {};this.onceQueue = {};}$on(name, callback) {this.queue[name] = this.queue[name] || [];this.queue[name].push(callback);}$once(name, callback) {this.onceQueue[name] = this.onceQueue[name] || [];this.onceQueue[name].push(callback);}$off(name, callback) {if (callback) {if (this.queue[name]) {for (var i = 0; i < this.queue[name].length; i++) {if (this.queue[name][i] === callback) {this.queue[name].splice(i, 1);break;}}}} else {delete this.queue[name];}}$emit(name, data) {if (this.queue[name]) {this.queue[name].forEach(function (callback) {callback(data);});}if (this.onceQueue[name]) {this.onceQueue[name].forEach(function (callback) {callback(data);});delete this.onceQueue[name];}}
}export default new Event();
使用
import Bus from '@/utils/EventBus';
Bus.$on('test', (data) => {})
Bus.$emit('close')
beforeUnmount() {
Bus.$off('test', fun)
}
构造函数方式
function E() { }// 函数E的原型对象
E.prototype = {// on方法:接受订阅名,订阅函数,上下文对象on: function (name, callback, context) {// 初始化e仓库var e = this.e || (this.e = {})// 收集订阅函数// 包装为对象,收集订阅函数与上下文对象; (e[name] || (e[name] = [])).push({fn: callback,context})// 返回实例对象return this},// once函数:接收订阅名,订阅函数,上下文对象// 与on的区别是:once函数收集只执行一遍的订阅函数once: function (name, callback, context) {let self = this// 包装对象,用于自定义执行逻辑(删除操作)function listener() {self.off(name, listener)callback.apply(context, arguments)}// 保存原始函数listener._ = callback// 使用on收集自定义后的函数// 执行on方法会返回this,所以once函数内不需要返回thisreturn this.on(name, listener, context)},// emit方法用于触发订阅函数:接收订阅名称emit: function (name) {// 收集参数let args = [].slice.call(arguments, 1)// 收集订阅函数数组let events = ((this.e || (this.e = {}))[name] || []).slice()let i = 0let len = events.length// 循环执行订阅函数for (; i < len; i++) {// 使用apply调用函数并绑定thisevents[i].fn.apply(events[i].context, args)}// 返回this实例return this},// off用于删除订阅函数:接收订阅名和订阅函数off: function (name, callback) {let e = this.e || (this.e = {})// 获取订阅名称对应的数组let events = e[name]let liveEvents = []// 处理函数数组&传入的订阅函数是否都存在?if (events && callback) {// 循环遍历,过滤操作for (let i = 0, len = events.length; i < len; i++) {// 判断数组中的订阅函数是否与传入的订阅函数相等?// 使用once创建的函数取_属性中的原始函数进行对比if (events[i].fn !== callback && events[i].fn._ !== callback) {liveEvents.push(events[i])}}}// 重置订阅名结果数组(liveEvents.length) ? e[name] = liveEvents : delete e[name]// 返回实例thisreturn this}
}export default {$on: (...args) => E.prototype.on(...args),$once: (...args) => E.prototype.once(...args),$off: (...args) => E.prototype.off(...args),$emit: (...args) => E.prototype.emit(...args)
}
使用
import Bus from "@/utils/EventBus2";
Bus.$on('test', (data) => {})
Bus.$emit('close')
beforeUnmount() {
Bus.$off('test', fun)
}