原生js实现事件总线

/**
 * 发布-订阅模式
 * 自定义的事件总线
 * 方法: 
 * on: 绑定一个事件
 * once: 绑定一个一次性事件
 * off: 移除一个事件
 * emit: 触发一个事件
 * use: 添加一个中间件
 * 
 * @author chengxg
 * @since 2018-12-29
 * @constructor
 */
export function EventBus() {
  this.eventArr = []; //事件列表
  this.useFunArr = []; //添加的中间件列表
}

export default new EventBus() //默认导出一个实例

//事件模板
const eventTpl = {
  name: "", //事件名
  isOnce: false, //是否只执行一次
  //回调
  callback: function () {

  }
}
/**
 * 创建一个事件
 * @param {String} name 
 * @param {Function} callback 
 * @return {eventTpl}
 */
EventBus.prototype.createEvent = function (name, callback) {
  return {
    name: name, //事件名
    isOnce: false, //是否只执行一次
    callback: callback //回调
  }
}

/**
 * 获取事件
 * @param {String} name 
 * @param {Function} fn 
 * @return {eventTpl}
 */
EventBus.prototype.getEvent = function (name, fn) {
  let matchFn = fn && typeof fn == 'function';
  return this.eventArr.filter((e) => {
    let b = e.name === name;
    if (matchFn) {
      b = b && e.fn === fn;
    }
    return b;
  })
}

/**
 * 移除一个事件
 * @param {String} name 
 * @param {Function} fn fn为空则全部移除
 * @return {void}
 */
EventBus.prototype.removeEvent = function (name, fn) {
  let matchFn = fn && typeof fn == 'function';
  this.eventArr = this.eventArr.filter((e) => {
    let b = e.name === name;
    if (matchFn) {
      b = b && e.fn === fn;
    }
    return !b;
  })
}

/**
 * 移除一个事件, 同removeEvent
 * @param {String} name 
 * @param {Function} fn fn为空则全部移除
 * @return {void}
 */
EventBus.prototype.off = function (name, fn) {
  this.removeEvent(name, fn);
}

/**
 * 添加中间件
 * @param {function(string, object, ()=>{})} fn 中间件函数 fn(name, packet, next)
 * @return {void}
 */
EventBus.prototype.use = function (fn) {
  this.useFunArr.push(fn)
}

/**
 * 中间件过滤, 只有添加的中间件执行next(),
 * 才会触发下一个中间件, 
 * 否则终止触发事件
 * @param {String} name 触发事件名
 * @param {Object} packet 触发事件传入的数据
 * @return {boolean} b
 */
EventBus.prototype.useFilter = function (name, packet) {
  let useFunArr = this.useFunArr;
  let len = useFunArr.length;
  let index = 0;
  if (len) {
    //从第一个中间件开始执行
    useFunArr[0](name, packet, next);
    //执行过的中间件与中间件总数相比较
    if (index === len - 1) {
      return true;
    } else {
      return false;
    }
  }
  return true;

  function next() {
    //每执行一个中间件,指数+1
    index++;
    if (index < len) {
      useFunArr[index](name, packet, next);
    }
  }
}

/**
 * 添加事件
 * @param {String} name 事件名
 * @param {Function} fn 执行的事件函数
 * @param {boolean} cover 是否覆盖之前的事件
 * @return {eventTpl}
 */
EventBus.prototype.on = function (name, fn, cover = false) {
  let ev = this.createEvent(name, fn);
  if (cover) {
    let eventArr = this.getEvent(name);
    if (eventArr.length > 0) {
      this.removeEvent(name);
    }
  }
  this.eventArr.push(ev);
  return ev;
}

/**
 * 添加事件, 执行完立即立即销毁
 * @param {String} name 事件名
 * @param {Function} fn 执行的事件函数
 * @param {boolean} cover 是否覆盖之前的事件
 * @return {void}
 */
EventBus.prototype.once = function (name, fn, cover = false) {
  let ev = this.on(name, fn, cover);
  ev.isOnce = true;
}

/**
 * 触发一个事件
 * @param {String} name 事件名
 * @param {Object} data 传入事件监听方法的数据
 * @return {void}
 */
EventBus.prototype.emit = function (name, data) {
  let eventArr = this.getEvent(name);
  let b = this.useFilter(name, data);
  if (!b) {
    return;
  }
  let len = eventArr.length,
    ev;
  for (let i = 0; i < len; i++) {
    ev = eventArr[i];
    //执行监听的事件
    if (typeof ev.callback === 'function') {
      let b = ev.callback(data);
      if (ev.isOnce) {
        this.removeEvent(event);
      }
      if (typeof b != 'undefined' && b === false) {
        return;
      }
    }
  }
}

 

你可能感兴趣的:(web前端)