JS高级 之 eventBus 事件总线

目录

一、概念

二、手写

1. 代码

2. 栗子 🌰

三、Vue2 中

1. 在 main.js 中注册

2. 在某组件发射事件

3. 在某组件监听事件         

4. 移除事件 

四、Vue3 中

1. 安装

2. 封装一下

3. 发射事件 

4. 监听事件

5. 取消事件


一、概念

事件总线也是一种通信方式,只不过它的功能比较强大,不在局限于父传子或兄弟组件之间通信,它可以跨组件通信,通过事件总线传递的值,不管哪个组件都可以获取到

 

总而言之,可以在各个模块中通信并且传递数据

事件总线属于一种观察者模式,其中包括三个角色 : 

  • 发布者(Publisher):发出事件(Event)
  • 订阅者(Subscriber):订阅事件(Event),并且会进行响应(Handler)
  • 事件总线(EventBus):无论是发布者还是订阅者都是通过事件总线作为中台的

二、手写

1. 代码

class StarEventBus {
  constructor() {
    // 事件名称 和 方法的映射关系
    this.eventMap = {};
  }
  /**
   *  监听
   *  因为可能有相同的名字监听,但是回调函数不一样
   *  所以使用数组存储
   */
  on(eventName, fn) {
    if (!this.eventMap[eventName]) {
      this.eventMap[eventName] = [];
    }
    this.eventMap[eventName].push(fn);
  }
  /**
   * 发射事件
   * 一发射就自动调用方法
   */
  emit(eventName, ...args) {
    if (!this.eventMap[eventName]) return;
    this.eventMap[eventName].forEach((fn) => {
      fn(...args);
    });
  }
  /**
   * 删除事件
   * 删除事件名和其对应的函数
   */
  off(eventName, fn) {
    if (!this.eventMap[eventName]) return;

    // 可能拥有相同的事件名和相同的函数,所以循环删除
    this.eventMap[eventName].forEach((itemFn, index) => {
      if (itemFn === fn) {
        // 使其位置还在,不过是为空
        delete this.eventMap[eventName][index];
      }
    });
    // 过滤空的值
    this.eventMap[eventName] = this.eventMap[eventName].filter((item) => item);

    // 如果eventFns已经清空了
    if (this.eventMap[eventName].length === 0) {
      delete this.eventMap[eventName];
    }
  }
  /**
   * 清空事件名对应的事件函数数组
   */
  clear(eventName) {
    if (!this.eventMap[eventName]) return;
    delete this.eventMap[eventName];
  }
  /**
   * 清空所有事件
   */
  clearAll() {
    this.eventMap = {};
  }
}

2. 栗子 🌰

// 1. 创建对象
const eventBus = new StarEventBus();

// 2. 监听方法
eventBus.on('btnClick', () => {
  console.log('俺被惦记了');
});

const btnClick = () => {
  console.log('俺也被惦记了');
};
eventBus.on('btnClick', btnClick);

setTimeout(() => {
  // 4. 删除方法
  eventBus.off('btnClick', btnClick);
}, 3000);

const btnDom = document.querySelector('button');
btnDom.onclick = function () {
  console.log('btn 点击');
  // 3. 发射方法
  eventBus.emit('btnClick');
};

三、Vue2 中

Vue2默认是带有事件总线的功能,因为vue实例自带了以下方法

1. 在 main.js 中注册

// 在入口 main.js 中,创建一个 bus 总线,这样全局都可以使用
Vue.prototype.$bus = new Vue()

2. 在某组件发射事件

<template>
  <button @click="btnClick">发射</button>
</template>
 
<script> 
export default {
  methods: {
    btnClick() {
      this.$bus.$emit("emitFn", '我来啦!!!');
    }
  }
}; 

3. 在某组件监听事件         

<template>
  <div>test</div>
</template>
 
<script> 
export default {
  mounted() {
    // 监听 emitFn 事件
    this.$bus.$on("emitFn", (res) => {
      console.log(res) // 我来啦!!!
    });

    // 只会促发一次的监听
    this.$bus.$once("gulugulu", (res) => {
      console.log('once') // once
    });
  }
};

4. 移除事件 

<template>
  <div>test</div>
</template>
 
<script> 
export default {
  mounted() {
    // 监听 emitFn 事件
    this.$bus.$on("emitFn", this.sayHello);
  },
  methods: {
    sayHello(res) {
        console.log(res) // 我来啦!!!
    }
  },
  // 移除事件
  beforeDestroy() {
    this.$bus.$off("emitFn")
    // this.$bus.$off("emitFn", this.sayHello)
  }
};

四、Vue3 中

Vue3中推荐一些第三方库,比如mitt

1. 安装

npm install mitt

2. 封装一下

新建eventbus.js

// 导入
import mitt from 'mitt';
// 创建
const emitter = mitt();
// 导出
export default emitter;

3. 发射事件 

<template>
  <div class="son-layout">
    <button @click="emitSon">son</button>
  </div>
</template>
<script>
// 导入封装的
import emitter from '../assets/eventBus';
export default {
  name: 'son',
  methods: {
    emitSon() {
      console.log('我发射啦');
      // 使用
      emitter.emit('sonEmit', { name: '我是son' });
    }
  }
};
</script>
<style></style>

4. 监听事件

<template>
  <div class="zhong-layout">zhong</div>
</template>
<script>
// 导入
import emitter from '../assets/eventBus';
export default {
  name: 'zhong',
  mounted() {
    // 监听sonEmit事件
    emitter.on('sonEmit', (value) => {
      console.log(value.name, '收到啦');
    });

    // 监听所有事件  type : 事件的名字  info:对应的数据
    // 如果有两个事件,会执行两次,不会有冲突哒~
    emitter.on('*', (type, info) => {
      console.log(info);
      console.log('* listener', type, info);
    });
  },
};
</script>
<style>
</style>

5. 取消事件

// 取消所有的事件监听
emitter.all.clear()

// 取消指定事件监听,方法要使用同一个 如 : sonEmit. 
function onFoo(){}
emitter.on('sonEmit', onFoo)
emitter.off('sonEmit', onFoo)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值