做了个面试题:使用TDD思想,用vue3集成自己手写的event bus。

一些集成的就比较简单就不介绍了,直接看单测

import { EventBus } from "../plugin/EventBus";
const bus = new EventBus();

describe("实现:事件车(发布订阅模式)", () => {

  it("event bus on", () => {
    const muckFn = jest.fn();
    bus.on("event one", muckFn);
    expect(bus.eventsMap.size).toBe(1)
  });
  // 事件监听 on这个功能 使用muck一个fn 看bus.eventMap这个集合中的 数量 是否放入中了

  it("event bus emit", () => {
    const muckFn = jest.fn();
    bus.on("event one", muckFn);
    bus.emit("event one", '1111111111111111111');
    bus.emit("event one", '2222222222222222222');
    bus.emit("event one", '3333333333333333333');
    expect(muckFn).toBeCalledTimes(3)
  });

  // 发送事件 看muck的fn调用次数 是不是三次

  it("event bus off", () => {
    const muckFn = jest.fn();
    bus.on("event one", muckFn);
    bus.emit("event one", '1111111111111111111');
    bus.off("event one", muckFn);
    bus.emit("event one", '1111111111111111111');
    expect(muckFn).toBeCalledTimes(1)
  });

  // 主要是看off之后是否函数继续调用


  it("event bus once", () => {
    const muckFn = jest.fn();
    bus.once("event once", muckFn);
    bus.emit("event once", '1111111111111111111');
    bus.emit("event once", '1111111111111111111');
    bus.emit("event once", '1111111111111111111');
    bus.emit("event once", '1111111111111111111');
    expect(muckFn).toBeCalledTimes(1)
  });

  // 主要是看once创建的是否会接收多次

});

现在开始具体实现逻辑。

首先将任务拆分: 

1、实现on是要将传入的函数和事件名存储到一个数据容器中,我选择的是Set()。

2、现在先写一个类,并先要声明存储的数据容器

export class EventBus {
  constructor() {
    this.eventsMap = new Set();
  }
}

3、on实现:就是将这里的内容存储到容器中


  on(eveName, cb) {
    this.eventsMap.add({
      eveName,
      callback: cb,
    });
  }

4、emit实现:在调用时寻找容器中时间名和传入的事件名相等的项,调用函数,并将参数传入


  emit(eveName, ...args) {
    const eventSet = this.eventsMap;
    for (const item of eventSet) {
      if (item.eveName == eveName) {
        item.callback(...args);
        if (item.once) {
          eventSet.delete(item);
        }
      }
    }
  }

5、once实现:与on相似只是使用了一个属性标识只执行一次。


  once(eveName, cb) {
    this.eventsMap.add({
      eveName,
      callback: cb,
      once: true,
    });
  }

6、off实现:就是在调用时在容器寻找与传入事件名相同的项,并删除。


  off(eveName) {
    const eventSet = this.eventsMap;
    for (const item of eventSet) {
      if (item.eveName == eveName) {
        this.eventsMap.delete(item);
      }
    }
  }

最后的单侧结果:

7、将插件集成到vue3中:

export default {
  install(app) {
    // 挂载到原型 app.config.globalProperties 方式
    const eventBus = new EventBus();
    app.config.globalProperties.$bus = eventBus;
  },
};

 8、在main.js使用use进行注册:

import { createApp } from "vue";
import mountEventBus from "./plugin/EventBus";
import App from "./App.vue";


const app = createApp(App);
app.use(mountEventBus).mount("#app");

9、在vue3的组件内使用:

<template>
  <div>
    <HelloWorld></HelloWorld>
  </div>
</template>

<script>
import { getCurrentInstance } from 'vue'
import HelloWorld from './components/HelloWorld.vue';
export default {
  components: { HelloWorld },
  setup() {
    const { proxy } = getCurrentInstance()
    proxy.$bus.on('hahha', (...args) => {
      console.log(...args);
    })
    return {
      
    }
  }
}
</script>

猜你喜欢

转载自blog.csdn.net/qq_44560147/article/details/126516359
今日推荐