
目录
事件总线也是一种通信方式,只不过它的功能比较强大,不在局限于父传子或兄弟组件之间通信,它可以跨组件通信,通过事件总线传递的值,不管哪个组件都可以获取到
总而言之,可以在各个模块中通信并且传递数据
事件总线属于一种观察者模式,其中包括三个角色 :
- 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 = {};
- }
- }
- // 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默认是带有事件总线的功能,因为vue实例自带了以下方法
- // 在入口 main.js 中,创建一个 bus 总线,这样全局都可以使用
- Vue.prototype.$bus = new Vue()
- <template>
- <button @click="btnClick">发射button>
- template>
-
- <script>
- export default {
- methods: {
- btnClick() {
- this.$bus.$emit("emitFn", '我来啦!!!');
- }
- }
- };
- <template>
- <div>testdiv>
- template>
-
- <script>
- export default {
- mounted() {
- // 监听 emitFn 事件
- this.$bus.$on("emitFn", (res) => {
- console.log(res) // 我来啦!!!
- });
-
- // 只会促发一次的监听
- this.$bus.$once("gulugulu", (res) => {
- console.log('once') // once
- });
- }
- };
- <template>
- <div>testdiv>
- 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中推荐一些第三方库,比如mitt
npm install mitt
新建eventbus.js
- // 导入
- import mitt from 'mitt';
- // 创建
- const emitter = mitt();
- // 导出
- export default emitter;
- <template>
- <div class="son-layout">
- <button @click="emitSon">sonbutton>
- div>
- template>
- <script>
- // 导入封装的
- import emitter from '../assets/eventBus';
- export default {
- name: 'son',
- methods: {
- emitSon() {
- console.log('我发射啦');
- // 使用
- emitter.emit('sonEmit', { name: '我是son' });
- }
- }
- };
- script>
- <style>style>
- <template>
- <div class="zhong-layout">zhongdiv>
- 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>
- // 取消所有的事件监听
- emitter.all.clear()
-
- // 取消指定事件监听,方法要使用同一个 如 : sonEmit.
- function onFoo(){}
- emitter.on('sonEmit', onFoo)
- emitter.off('sonEmit', onFoo)