• JS高级 之 eventBus 事件总线


    目录

    一、概念

    二、手写

    1. 代码

    2. 栗子 🌰

    三、Vue2 中

    1. 在 main.js 中注册

    2. 在某组件发射事件

    3. 在某组件监听事件         

    4. 移除事件 

    四、Vue3 中

    1. 安装

    2. 封装一下

    3. 发射事件 

    4. 监听事件

    5. 取消事件


    一、概念

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

     

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

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

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

    二、手写

    1. 代码

    1. class StarEventBus {
    2. constructor() {
    3. // 事件名称 和 方法的映射关系
    4. this.eventMap = {};
    5. }
    6. /**
    7. * 监听
    8. * 因为可能有相同的名字监听,但是回调函数不一样
    9. * 所以使用数组存储
    10. */
    11. on(eventName, fn) {
    12. if (!this.eventMap[eventName]) {
    13. this.eventMap[eventName] = [];
    14. }
    15. this.eventMap[eventName].push(fn);
    16. }
    17. /**
    18. * 发射事件
    19. * 一发射就自动调用方法
    20. */
    21. emit(eventName, ...args) {
    22. if (!this.eventMap[eventName]) return;
    23. this.eventMap[eventName].forEach((fn) => {
    24. fn(...args);
    25. });
    26. }
    27. /**
    28. * 删除事件
    29. * 删除事件名和其对应的函数
    30. */
    31. off(eventName, fn) {
    32. if (!this.eventMap[eventName]) return;
    33. // 可能拥有相同的事件名和相同的函数,所以循环删除
    34. this.eventMap[eventName].forEach((itemFn, index) => {
    35. if (itemFn === fn) {
    36. // 使其位置还在,不过是为空
    37. delete this.eventMap[eventName][index];
    38. }
    39. });
    40. // 过滤空的值
    41. this.eventMap[eventName] = this.eventMap[eventName].filter((item) => item);
    42. // 如果eventFns已经清空了
    43. if (this.eventMap[eventName].length === 0) {
    44. delete this.eventMap[eventName];
    45. }
    46. }
    47. /**
    48. * 清空事件名对应的事件函数数组
    49. */
    50. clear(eventName) {
    51. if (!this.eventMap[eventName]) return;
    52. delete this.eventMap[eventName];
    53. }
    54. /**
    55. * 清空所有事件
    56. */
    57. clearAll() {
    58. this.eventMap = {};
    59. }
    60. }

    2. 栗子 🌰

    1. // 1. 创建对象
    2. const eventBus = new StarEventBus();
    3. // 2. 监听方法
    4. eventBus.on('btnClick', () => {
    5. console.log('俺被惦记了');
    6. });
    7. const btnClick = () => {
    8. console.log('俺也被惦记了');
    9. };
    10. eventBus.on('btnClick', btnClick);
    11. setTimeout(() => {
    12. // 4. 删除方法
    13. eventBus.off('btnClick', btnClick);
    14. }, 3000);
    15. const btnDom = document.querySelector('button');
    16. btnDom.onclick = function () {
    17. console.log('btn 点击');
    18. // 3. 发射方法
    19. eventBus.emit('btnClick');
    20. };

    三、Vue2 中

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

    1. 在 main.js 中注册

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

    2. 在某组件发射事件

    1. <template>
    2. <button @click="btnClick">发射button>
    3. template>
    4. <script>
    5. export default {
    6. methods: {
    7. btnClick() {
    8. this.$bus.$emit("emitFn", '我来啦!!!');
    9. }
    10. }
    11. };

    3. 在某组件监听事件         

    1. <template>
    2. <div>testdiv>
    3. template>
    4. <script>
    5. export default {
    6. mounted() {
    7. // 监听 emitFn 事件
    8. this.$bus.$on("emitFn", (res) => {
    9. console.log(res) // 我来啦!!!
    10. });
    11. // 只会促发一次的监听
    12. this.$bus.$once("gulugulu", (res) => {
    13. console.log('once') // once
    14. });
    15. }
    16. };

    4. 移除事件 

    1. <template>
    2. <div>testdiv>
    3. template>
    4. <script>
    5. export default {
    6. mounted() {
    7. // 监听 emitFn 事件
    8. this.$bus.$on("emitFn", this.sayHello);
    9. },
    10. methods: {
    11. sayHello(res) {
    12. console.log(res) // 我来啦!!!
    13. }
    14. },
    15. // 移除事件
    16. beforeDestroy() {
    17. this.$bus.$off("emitFn")
    18. // this.$bus.$off("emitFn", this.sayHello)
    19. }
    20. };

    四、Vue3 中

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

    1. 安装

    npm install mitt

    2. 封装一下

    新建eventbus.js

    1. // 导入
    2. import mitt from 'mitt';
    3. // 创建
    4. const emitter = mitt();
    5. // 导出
    6. export default emitter;

    3. 发射事件 

    1. <template>
    2. <div class="son-layout">
    3. <button @click="emitSon">sonbutton>
    4. div>
    5. template>
    6. <script>
    7. // 导入封装的
    8. import emitter from '../assets/eventBus';
    9. export default {
    10. name: 'son',
    11. methods: {
    12. emitSon() {
    13. console.log('我发射啦');
    14. // 使用
    15. emitter.emit('sonEmit', { name: '我是son' });
    16. }
    17. }
    18. };
    19. script>
    20. <style>style>

    4. 监听事件

    1. <template>
    2. <div class="zhong-layout">zhongdiv>
    3. template>
    4. <script>
    5. // 导入
    6. import emitter from '../assets/eventBus';
    7. export default {
    8. name: 'zhong',
    9. mounted() {
    10. // 监听sonEmit事件
    11. emitter.on('sonEmit', (value) => {
    12. console.log(value.name, '收到啦');
    13. });
    14. // 监听所有事件 type : 事件的名字 info:对应的数据
    15. // 如果有两个事件,会执行两次,不会有冲突哒~
    16. emitter.on('*', (type, info) => {
    17. console.log(info);
    18. console.log('* listener', type, info);
    19. });
    20. },
    21. };
    22. script>
    23. <style>
    24. style>

    5. 取消事件

    1. // 取消所有的事件监听
    2. emitter.all.clear()
    3. // 取消指定事件监听,方法要使用同一个 如 : sonEmit.
    4. function onFoo(){}
    5. emitter.on('sonEmit', onFoo)
    6. emitter.off('sonEmit', onFoo)

  • 相关阅读:
    《用Go语言自制解释器》之第5章 宏系统
    opencv入门到精通——图片,视频,摄像头的读取与保存
    后端返回base64文件流下载
    橘子学JVM之命令行监控06之jcmd
    1470. Shuffle the Array
    时间序列(四):单变量时间序列的神经网(LSTM)
    PostgreSQL进阶
    精彩预告 | OpenHarmony即将亮相MTSC 2023
    C语言查找幸运数字(ZZULIOJ1056:幸运数字)
    常见钓鱼手法及防范
  • 原文地址:https://blog.csdn.net/a15297701931/article/details/126725260