Vue2-Vue3组件间通信-EventBus方式-函数封装

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函数内不需要返回this
        return 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 = 0
        let len = events.length
        // 循环执行订阅函数
        for (; i < len; i++) {
            // 使用apply调用函数并绑定this
            events[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]
        // 返回实例this
        return 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)
}

posted @ 2023-07-31 18:02  JackieDYH  阅读(235)  评论(0编辑  收藏  举报  来源