发布订阅模式

93 阅读1分钟

发布订阅模式可以用公众号来进行比喻,好多账号关注了一个公众号就相当于订阅,当公众号有信息需要发布时,就会依次通知订阅了公众号的账号。 可以用js来模拟这个操作,主要方法有

  • $on 订阅

  • $emit 通知发布

  • $off 取消订阅

  • $once 只执行一次

  • 首先定义对象用来存储方法

let EventObj = {

}
  • 对象上添加$on方法,用来订阅事件

参数是 fnName:订阅的事件名 fn:事件绑定的方法

我们使用数组来保存订阅的事件列如 fnName:[fn1,fn2,fn3.....]。首先判断是否订阅了fnNmae,订阅了就向数组添加方法,没有订阅就先创建数组再添加方法。

EventObj.$on = function (fnName, fn) {
    if (EventObj[fnName]) {
        EventObj[fnName].push(fn)
    } else {
        EventObj[fnName] = []
        EventObj[fnName].push(fn)
    }
}
  • 对象上添加$emit方法,用来发布通知订阅事件

参数是 fnName:订阅的事件名 args:事件的参数

判断EventObj里面是否有订阅的事件,也就是EventObj[fnName]这个数组是否有值,有的话就通知数组里面的方法依次执行。

EventObj.$emit = function (fnName, ...args) {
    if (EventObj[fnName] && EventObj[fnName].length > 0) {
        EventObj[fnName].forEach(element => {
            element(args)
        });
    } else {
        console.log('未订阅事件');
    }
}
  • 对象上添加$off方法,用来取消订阅事件

参数是 fnName:订阅的事件名

判断EventObj里面是否有订阅的事件,有的话,删除事件数组就行

EventObj.$off = function (fnName) {
    if (EventObj[fnName]) {
        delete EventObj[fnName]
    } else {
        console.log('未订阅事件off');
    }
}
  • 对象上添加$once方法,只执行一次订阅事件

参数是 fnName:订阅的事件名 fn:事件绑定的方法

只执行一次,所以我们可以在首次执行后,调用off来取消就行,那就需要把执行和取消的代码放到一个方法里面,缓存起来,再用off来取消就行,那就需要把执行和取消的代码放到一个方法里面,缓存起来,再用on方法进行订阅。

EventObj.$once = function (fnName, fn) {
    let newFn = () => {
        fn()
        this.$off(fnName)
    }
    this.$on(fnName, newFn)
}

全部代码如下

let EventObj = {

}
EventObj.$on = function (fnName, fn) {
    if (EventObj[fnName]) {
        EventObj[fnName].push(fn)
    } else {
        EventObj[fnName] = []
        EventObj[fnName].push(fn)
    }
}
EventObj.$emit = function (fnName, ...args) {
    if (EventObj[fnName] && EventObj[fnName].length > 0) {
        EventObj[fnName].forEach(element => {
            element(args)
        });
    } else {
        console.log('未订阅事件');
    }
}
EventObj.$once = function (fnName, fn) {
    let newFn = () => {
        fn()
        this.$off(fnName)
    }
    this.$on(fnName, newFn)
}
EventObj.$off = function (fnName) {
    if (EventObj[fnName]) {
        delete EventObj[fnName]
    } else {
        console.log('未订阅事件off');
    }
}
function addfun() {
    console.log(555);
}
EventObj.$once('add', addfun)
EventObj.$emit('add')
EventObj.$emit('add')

有啥不对的,请大佬指点