Vue笔记(十二)--mitt

这一节了解一下Vue3中的mitt,mitt是Vue3中最常用的轻量级事件总线库,本质是一个基于发布-订阅模式的独立EventEmitter,总结如下:

API:

emitter.on(event, handler):监听事件,注册回调函数,当事件触发时执行

emitter.emit(event, data):触发事件,发布事件并携带数据,通知所有监听者

emitter.off(event, handler):取消监听, 移除指定事件的指定回调,防止内存泄漏

emitter.all.clear():清空所有监听,一次性移除所有事件的所有回调

场景

1 兄弟组件/非父子组件通信:两个无直接关系的组件需要传递消息。

2 全局通知/消息提示:任意组件触发全局Toast、Notification等。

3 跨多层组件传递消息:避免props逐层透传。

栗子:

TypeScript 复制代码
src/utils/eventBus.ts

import mitt from 'mitt'

const emitter = mitt()
export default emitter
TypeScript 复制代码
发送方BrotherA.vue

<template>
  <div style="border:1px solid #ccc;padding:10px;margin:8px;">
    <h3>兄弟A(发送方)</h3>
    <button @click="sendMsg">给兄弟B发送消息</button>
  </div>
</template>

<script setup lang="ts">
import emitter from '@/utils/eventBus'

const sendMsg = () => {
  emitter.emit('send-to-b', {
    name: '兄弟A',
    content: '你好,我是A组件消息'
  })
}
</script>
TypeScript 复制代码
接收方 BrotherB.vue

<template>
  <div style="border:1px solid #ccc;padding:10px;margin:8px;">
    <h3>兄弟B(接收方)</h3>
    <p>收到消息:{{msg}}</p>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import emitter from '@/utils/eventBus'

const msg = ref('')

onMounted(() => {
  emitter.on('send-to-b', (data) => {
    msg.value = `${data.name}:${data.content}`
  })
})


onBeforeUnmount(() => {
  emitter.off('send-to-b')
})
</script>
TypeScript 复制代码
App.vue

<template>
  <BrotherA />
  <BrotherB />
</template>

<script setup lang="ts">
import BrotherA from './components/BrotherA.vue'
import BrotherB from './components/BrotherB.vue'
</script>

Demo2

TypeScript 复制代码
src/utils/eventBus.ts

import mitt from 'mitt'

type EventType = {
  'submit-form': { username: string; password: string }
  'global-notice': string
}

const emitter = mitt<EventType>()
export default emitter
TypeScript 复制代码
src/composables/useEventBus.ts

import emitter from '@/utils/eventBus'
import { onBeforeUnmount } from 'vue'

export function useEventBus() {
  const handlers: Array<() => void> = []

  const on = <T extends keyof EventType>(event: T, callback: (data: EventType[T]) => void) => {
    emitter.on(event, callback)
    handlers.push(() => emitter.off(event, callback))
  }

  const emit = <T extends keyof EventType>(event: T, data: EventType[T]) => {
    emitter.emit(event, data)
  }

  onBeforeUnmount(() => {
    handlers.forEach(unbind => unbind())
  })

  return { on, emit }
}
TypeScript 复制代码
FormSubmit.vue

<template>
  <div style="border:1px solid #ccc;padding:12px;">
    <h3>表单组件</h3>
    <input v-model="form.username" placeholder="用户名"/>
    <input v-model="form.password" placeholder="密码"/>
    <button @click="handleSubmit">提交表单</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useEventBus } from '@/composables/useEventBus'

const { emit } = useEventBus()
const form = ref({
  username: '',
  password: ''
})

const handleSubmit = () => {
  emit('submit-form', form.value)
  emit('global-notice', '表单已提交成功!')
}
</script>
TypeScript 复制代码
GlobalTip.vue

<template>
  <div style="border:1px solid #42b983;padding:12px;margin-top:10px;">
    <h3>全局提示组件</h3>
    <p>表单数据:{{formInfo}}</p>
    <p>通知消息:{{tipMsg}}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useEventBus } from '@/composables/useEventBus'

const { on } = useEventBus()
const formInfo = ref('')
const tipMsg = ref('')

on('submit-form', (data) => {
  formInfo.value = `用户名:${data.username},密码:${data.password}`
})

on('global-notice', (msg) => {
  tipMsg.value = msg
})
</script>
TypeScript 复制代码
App.vue

<template>
  <FormSubmit />
  <GlobalTip />
</template>

<script setup lang="ts">
import FormSubmit from './components/FormSubmit.vue'
import GlobalTip from './components/GlobalTip.vue'
</script>

注意:

1 必须手动取消监听:组件卸载时务必调用off移除回调,否则回调函数会一直驻留内存,导致内存泄漏。

2 事件命名冲突:事件名是全局字符串,建议加命名空间前缀,避免不同模块间冲突。

相关推荐
用户0333074139513 小时前
TypeScript using 与 AsyncDisposableStack:在真实服务端代码中协调多资源清理
前端
daisychey13 小时前
用 Playwright 做多平台内容分发,我踩过的 8 个坑
前端
IT_陈寒14 小时前
为什么你应该学习JavaScript?
前端·人工智能·后端
大龄秃头程序员14 小时前
iOS冷启动监控Demo
前端
光影少年14 小时前
为什么 JavaScript 中 0.1 + 0.2 !== 0.3,如何让其相等?
前端·javascript·算法
掘金酱15 小时前
[稀土掘金 × 火山引擎] AI用量周榜冲刺赛|获奖名单公示
前端·人工智能·后端
泡泡oO15 小时前
“如果你还在用Superpowers,那我不要和你说话”
前端·后端·全栈
一隅论数智15 小时前
OWL(Web Ontology Language)介绍与使用举例(二)
大数据·经验分享·笔记·学习·自然语言处理·学习方法·政务
维克兜率天15 小时前
趋势过滤:避免被“假突破“反复打脸
前端