Vue 消息通知
在Vue中实现事件发布订阅(Event Bus)设计模式是一种允许不同组件之间进行通信的方式,尤其适用于那些没有直接父子关系的组件。这种模式使用一个中央事件总线(Event Bus),组件通过它来发布(emit)事件和订阅(on)事件。
这里是如何在Vue中实现这个模式的一个基本示例:
class VueEventSystem {
constructor() {
this.events = {};
}
$on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
$emit(eventName, ...args) {
if (this.events[eventName]) {
this.events[eventName].forEach(callback => callback(...args));
}
}
$off(eventName, callback) {
if (!this.events[eventName]) return;
if (!callback) {
this.events[eventName] = [];
return;
}
const index = this.events[eventName].indexOf(callback);
if (index !== -1) {
this.events[eventName].splice(index, 1);
}
}
$once(eventName, callback) {
const onceCallback = (...args) => {
callback(...args); // 执行回调
this.$off(eventName, onceCallback); // 立即解除订阅
};
this.$on(eventName, onceCallback);
}
}
完整代码示例:
// 构造函数
function VM () {
// 用来存放事件和方法
// 这里也可以选择了Map作为储存事件的结构,作为键值对的储存方式Map比一般对象更加适合
this.events = {}
}
// 监听方法
VM.prototype.$on = function (event, callback) {
if (Array.isArray(event)) {
for (let idx = 0, len = event.length; idx < len; idx++) {
this.$on(event[idx], callback)
}
} else {
(this.events[event] || (this.events[event] = [])).push(callback)
}
}
// 单次监听
VM.prototype.$once = function (event, callback) {
const _this = this
if (Array.isArray(event)) {
for (let idx = 0, len = event.length; idx < len; idx++) {
this.$once(event[idx], callback)
}
} else {
(this.events[event] || (this.events[event] = [])).push(function once (...arg) {
_this.$off(event, once)
callback.apply(_this, arg)
})
}
}
// 触发方法
VM.prototype.$emit = function (event, ...arg) {
if (Array.isArray(event)) {
for (let idx = 0, len = event.length; idx < len; idx++) {
this.$emit(event[idx], ...arg)
}
} else {
const listener = this.events[event]
if (listener) {
for (let idx = 0, len = listener.length; idx < len; idx++) {
listener[idx].apply(this, arg)
}
}
}
}
// 移除方法
VM.prototype.$off = function (event, callback) {
if (Array.isArray(event)) {
for (let idx = 0, len = event.length; idx < len; idx++) {
this.$off(event[idx], callback)
}
} else {
const listener = this.events[event]
if (listener) {
if (!callback) {
this.events[event] = []
} else {
for (let idx = 0, len = listener.length; idx < len; idx++) {
callback === listener[idx] && listener.splice(idx, 1)
}
}
}
}
}
// parent on hello
vm.$on('hello', function (a) {
console.log(a + ' comes hello')
})
// son emit hello
vm.$emit('hello', 'son')
vm.$emit('hello', 'lili')
// parent on hello
vm.$once('hi', function (a) {
console.log(a + ' comes hi')
})
// son emit hi
vm.$emit('hi', 'son')
vm.$emit('hi', 'lili')
vm.$emit('hi', 'lili')