一、 什么是发布-订阅模式
-
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
-
订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码
-
Vue3中不能再以New Vue来当做全局事件总线的处理方式,官方提供了mitt插件来替代New Vue实现全局跨组件通信,这里讲的是第二种方法,手写发布订阅模式来解决跨组件通信。
二、 实现思路
// 在utils文件夹下创建一个EventBus.js文件
const Bus = {
// map: 存储事件队列的 map, 每个事件都有一个单独的队列,存放所有的事件处理函数
map: new Map(),
// on: 订阅事件的方法,根据传入的 eventName 事件名,将handler追加到新建或存在的事件队列中
on(eventName, handler) {
const handlers = this.map.get(eventName)
if (handlers) {
handlers.push(handler)
} else {
this.map.set(eventName, [handler])
}
},
// emit: 触发事件的方法,根据传入事件名称、参数遍历事件队列并触发事件
emit(eventName, args) {
const handlers = this.map.get(eventName)
// console.log(handlers)
if (!handlers) {
throw new Error(`${eventName} is not exist`)
}
handlers.forEach((handler) => {
handler(args)
})
},
// off: 取消事件订阅,根据事件名和处理函数取消事件订阅,如不传入处理函数,则清空相应的事件队列
off(eventName, handler) {
if (!handler) {
this.map.set(eventName, [])
return
}
const handlers = this.map.get(eventName)
const index = handlers.indexOf(handler)
if (index >= 0) {
handlers.splice(index, 1)
}
},
// once: 执行单次事件订阅,触发后自动清除订阅
once(eventName, handler) {
const tempHandler = (args) => {
this.off(eventName, tempHandler)
handler(args)
}
this.on(eventName, tempHandler)
},
}
export default Bus
在组件中使用
// 需要被订阅的组件
import $bus from '@/utils/EventBus.js'
//组件实例挂载完毕订阅once方法(只触发一次)
onMounted(()=>{
$bus.once('factData',updataFn)
})
// 发布时会触发该方法
let updataFn=(item)=>{
// 通信的数据
console.log(item)
}
//需要发布的组件
import $bus from '@/utils/EventBus.js'
let clickLayout=()=>{
$bus.emit('factData',需要传递的参数)
}