Vue3 mitt 封装 cursor 回答版本

思维过程+观点标题 复制代码
# 1. 目标与需求分析

## 目标
- 适用于大型项目的 mitt 封装
- TypeScript 类型安全
- API 简单易用
- 维护简单,易于团队协作
- 支持 emit/on/once,自动解绑
- 便于扩展和文档化

# 2. 设计思路

- **事件类型集中管理**:统一在一个地方声明所有事件及其参数类型
- **API 设计**:只暴露 emit/on/once/clearAll,API 直观
- **自动解绑**:on/once 支持 setup 内自动解绑,setup 外返回手动解绑函数
- **类型安全**:emit/on/once 都有类型提示,参数类型强校验
- **文档注释**:每个 API 都有详细注释和示例

# 3. 代码实现

```typescript:src/common/mitt.ts
import { onUnmounted, getCurrentInstance } from 'vue'
import mitt, { Emitter } from 'mitt'

/**
 * 事件类型声明(大型项目建议集中管理)
 */
export interface AppEventMap {
  // 事件名: 参数类型
  userLogin: { userId: string }
  userLogout: void
  refreshList: { type: 'doc' | 'contact' }
  // ...更多事件
  [key: string]: any // 兼容动态事件
}

type EventName = keyof AppEventMap

const emitter: Emitter<AppEventMap> = mitt<AppEventMap>()

/**
 * 发送事件
 * @param eventName 事件名
 * @param payload 事件参数
 * @example
 * emit('userLogin', { userId: '123' })
 */
export function emit<K extends EventName>(eventName: K, payload: AppEventMap[K]): void {
  emitter.emit(eventName, payload)
}

/**
 * 监听事件(支持自动解绑)
 * @param eventName 事件名
 * @param handler 事件回调
 * @returns 返回解绑函数(setup 外部需手动调用)
 * @example
 * const off = on('userLogin', (payload) => { ... })
 * // setup 内自动解绑,无需关心
 * // setup 外部需手动调用 off()
 */
export function on<K extends EventName>(
  eventName: K,
  handler: (payload: AppEventMap[K]) => void
): () => void {
  emitter.on(eventName, handler)
  const off = () => emitter.off(eventName, handler)
  if (getCurrentInstance()) {
    onUnmounted(off)
  }
  return off
}

/**
 * 只监听一次事件
 * @param eventName 事件名
 * @param handler 事件回调
 * @example
 * once('userLogout', () => { ... })
 */
export function once<K extends EventName>(
  eventName: K,
  handler: (payload: AppEventMap[K]) => void
): void {
  const wrapper = (payload: AppEventMap[K]) => {
    handler(payload)
    emitter.off(eventName, wrapper)
  }
  emitter.on(eventName, wrapper)
  if (getCurrentInstance()) {
    onUnmounted(() => emitter.off(eventName, wrapper))
  }
}

/**
 * 清除所有事件监听
 * @example
 * clearAll()
 */
export function clearAll() {
  emitter.all.clear()
}

4. 用法示例

typescript 复制代码
// 发送事件
import { emit } from '@/common/mitt'
emit('userLogin', { userId: 'abc' })

// 监听事件(setup 内自动解绑)
import { on } from '@/common/mitt'
on('userLogin', (payload) => {
  console.log('登录', payload.userId)
})

// 监听事件(setup 外手动解绑)
const off = on('refreshList', (payload) => { ... })
// ...需要时调用 off()

// 只监听一次
import { once } from '@/common/mitt'
once('userLogout', () => {
  console.log('用户已登出')
})

// 清除所有事件
import { clearAll } from '@/common/mitt'
clearAll()

5. 维护与扩展建议

  • 事件类型统一管理 :所有事件类型都在 AppEventMap 里集中声明,便于团队协作和查找
  • API 直观统一:只用 emit/on/once/clearAll,团队成员易于理解和使用
  • 类型安全:参数类型错误会在编译期报错
  • 易于扩展 :如需全局事件、命名空间等,直接扩展 AppEventMap 或增加辅助函数即可

总结

这种 mitt 封装方式非常适合大型项目,API 简单、类型安全、易维护、易扩展,团队协作无障碍。只需记住四个 API:emitononceclearAll,事件类型集中管理,维护极其方便。

复制代码
相关推荐
EndingCoder几秒前
React从基础入门到高级实战:React 基础入门 - React Hooks 入门
前端·javascript·react.js·前端框架
EndingCoder1 分钟前
React从基础入门到高级实战:React 基础入门 - JSX与组件基础
前端·javascript·react.js·前端框架
Space Chars30 分钟前
【大前端】使用NodeJs HTTP模块创建web服务器、SSE通讯
服务器·前端·http
Quke陆吾1 小时前
Vue框架1(vue搭建方式1,vue指令,vue实例生命周期)
前端·javascript·vue.js
Oscar_02082 小时前
uniapp+ts 多环境编译
前端·vue.js·typescript·uni-app
shmily麻瓜小菜鸡2 小时前
前端项目中实现页面看起来像是浏览器缩放到了80%的效果
前端
EndingCoder2 小时前
从零基础到最佳实践:Vue.js 系列(9/10):《单元测试与端到端测试》
前端·javascript·vue.js·性能优化·单元测试·vue3
How_doyou_do2 小时前
Vue-创建应用/挂载应用/根组件模版-.vue单文件/应用配置
前端·javascript·vue.js
王者鳜錸3 小时前
Vue3集成Element Plus完整指南:从安装到主题定制下-实现后台管理系统框架搭建
前端·javascript·vue.js
YJlio3 小时前
优启通添加自定义浏览器及EXLOAD使用技巧分享
前端