mitt 是什么

  简单的说 mitt 就是一个全局的总线程,在 vue2.0中,我们经常会使用EventBus去处理问题,这时候你会说啥是总线程呢。更简单的说,其实就是发布订阅事件。

EventBus的简易源码

class Bus {
  constructor() {
    this.callback = {};
  }
  /**
   * @description: 发布事件
   * @param {*} name 名称
   * @param {*} fn 方法
   */
  $on(name, fn) {
    this.callback[name] = this.callback[name] || [];
    this.callback[name].push(fn);
  }
  /**
   * @description: 订阅器-接收器
   * @param {*} name 方法的名称
   * @param {*} args 入参
   */
  $emit(name, args) {
    if (this.callback[name]) {
      this.callback[name].forEach((cb) => {
        cb(args);
      });
    }
  }
}

// 挂载在 vue 的原型上
Vue.prototype.$bus = new Bus();

miit的使用

安装

npm install --save mitt

通常的使用

import mitt from 'mitt'

const emitter = mitt()

const TOPIC = 'topic'

// 订阅
emitter.on(TOPIC, (data)=>{
   console.log(data);
})   

// 发布事件
emitter.emit(TOPIC, { a: 'b' })

// 取消订阅
emitter.off(TOPIC, onFoo)

// 清空所有的事件
emitter.all.clear()

问题与痛点

命名问题

  每一次都需要去思考不重名,一旦使用重名,将很难定位问题

销毁事件

  事件都挂载到了总线程上,你需要思考如何去销毁掉订阅的事件,避免不必要的开销

为什么不去用 store去处理问题

  所有的问题存在则是必然,可为什么是必然呢?做一个假设,你现在处理一个表格数据的刷新,你是希望把表格数据放在 store 中还是放在业务组件中吗?很显然业务组件中,可以让代码的逻辑更加要区分,而不是把所有的数据,一股脑的放入 store 处理,这样代码的单一职责原则才能更好的体现。

hook 封装

useEventbus.ts

import { onUnmounted } from 'vue'
import mitt from 'mitt'

type IUseEventbus = {
  customEmit: (eventName: string) => void
  customOn: (eventName: string, callback: () => void) => void
  toRefreshTable: () => void
  refreshTable: (callback: () => void) => void
}

const emitter: mitt.Emitter = mitt()

/**
* @description: 自定义触发器
* @param {*} eventName 名称
*/
const customEmit = (eventName: string) => {
  emitter.emit(eventName)
}

/**
* @description: 自定义接收器
* @param {*} name 名称
* @param {*} callback 回调的函数
*/
const customOn = (eventName: string, callback: () => void) => {
  emitter.on(eventName, () => callback())
}

/**
* @description: 通知刷新表格数据
*/
const toRefreshTable = () => {
  emitter.emit('refreshTable')
}

/**
* @description: 刷新表格数据
* @param {*} callback 回调的函数
*/
const refreshTable = (callback: () => void) => {
  emitter.on('refreshTable', () => callback())
}

/**
* @description: 导出useEventbus
*/
export const useEventbus = (): IUseEventbus => {
  // 销毁的事件
  onUnmounted(() => {
    // 清空所有的事件,避免多组件互相清理
    emitter.all.clear()
  })
  
  return {
    customEmit,
    customOn,
    toRefreshTable,
    refreshTable
  }
}

main.vue - 主组件

<script lang="ts" setup>
import { onMounted } from 'vue';
import { useEventbus } from '@/hooks/useEventbus'

const eventbus = useEventbus()

onMounted(() => {
     // 订阅 init 方法
     eventbus.customOn('init', () => {
        init()
     })
})

const init = ()=>{
 // http
}
</script>

release.vue - 发布通讯组件

<script lang="ts" setup>
import { useEventbus } from '@/hooks/useEventbus'

const eventbus = useEventbus()

const handleClick = () => {
  // 发布通讯
  eventbus.customEmit('init')
}
</script>
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐