【Vue3】组件通信之mitt
背景
随着年龄的增长,很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来,技术出身的人总是很难放下一些执念,遂将这些知识整理成文,以纪念曾经努力学习奋斗的日子。本文内容并非完全原创,大多是参考其他文章资料整理所得,感谢每位技术人的开源精神。
简介
本文介绍 Vue3 中如何使用 mitt
实现任意组件间传数据。
Vue3 推荐使用 Mitt 作为事件总线(EventBus)实现平行组件间传数据。
Vue3 中组件间通信包括:
- 父组件向子组件传数据,实现方案有:
props
v-model
$ref
- 默认插槽 / 具名插槽
- 子组件向父组件传数据
props
v-model
$parent
- 自定义事件
- 作用域插槽
- 父组件向子组件的子组件传数据,即向孙子组件传数据
$attrs
provider
&inject
- 任意组件间传数据
mitt
Pinia
开发环境
分类 | 名称 | 版本 |
---|---|---|
操作系统 | Windows | Windows 11 |
IDE | Visual Studio Code | 1.91.1 |
开发步骤及源码
1> 创建 Vue3 工程,参考:【Vue3】工程创建及目录说明。
2> 执行 npm i mitt
命令安装 mitt
。
PS D:\...> npm i mitt
added 1 package in 1s
10 packages are looking for funding
run `npm fund` for details
3> 在 src
下新建 tools
/ utils
工具文件夹,在其中新建 emitter.ts
。
// 引入mitt
import mitt from 'mitt'
// 调用mitt得到emitter,emitter可以订阅事件及发布事件
const emitter = mitt()
// 暴露emitter
export default emitter
4> 修改 src
目录下 main.ts
,引入 emitter
。
import { createApp } from 'vue'
import App from './App.vue'
import emitter from './tools/emitter'
createApp(App).mount('#app')
5> 删除 src
目录下 assets
和 components
目录中内容。
6> 在 src/components
新建订阅事件的组件。
<template>
<div class="media">
<h2>Breaking News:</h2>
<ul>
<li v-for="item in news" :key="item.time">{{ item.time }} : {{ item.title }}</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { onUnmounted, reactive } from 'vue'
import emitter from '@/tools/emitter'
const news = reactive<any>([])
emitter.on('news', (value) => {
news.push(value)
})
// 组件卸载时需要主动解绑事件
onUnmounted(() => {
emitter.off('news')
})
</script>
<style scoped lang="scss">
.media {
background-color: coral;
height: 600px;
padding: 10px;
}
</style>
注意:需要执行 npm install -D sass
命令安装 CSS 预处理器。
7> 在 src/components
新建发布事件的组件。
<template>
<div class="reporter">
<h2>Reporter</h2>
<button @click="report">报道新闻</button>
</div>
</template>
<script setup lang="ts">
import emitter from '@/tools/emitter'
function report() {
emitter.emit('news', {
title: 'Breaking news...',
time: getDateTime(),
})
}
function getDateTime() {
const dateTime = new Date()
return dateTime.getFullYear()
+ '/' + (dateTime.getMonth() + 1)
+ '/' + dateTime.getDate()
+ ' ' + dateTime.getHours()
+ ':' + dateTime.getMinutes()
+ ':' + dateTime.getSeconds()
}
</script>
<style scoped lang="scss">
.reporter {
background-color: darkcyan;
padding: 10px;
button {
font-size: 18px;
font-weight: bold;
height: 30px;
width: 120px;
}
}
</style>
8> 修改 Vue 根组件 src/App.vue
作为最顶层组件,引入以上两个组件。
<template>
<div class="content">
<div class="component"><Media /></div>
<div class="component"><Reporter /></div>
</div>
</template>
<script setup lang="ts">
import Media from './components/Media.vue'
import Reporter from './components/Reporter.vue'
</script>
<style scoped lang="scss">
.content {
background-color: darkgray;
padding: 20px;
display: flex;
.component {
width: 500px;
margin-right: 30px;
}
}
</style>
9> 执行命令 npm run dev
启动应用,浏览器访问:http://localhost:5173/
,每点击一次 Reporter
组件中的 报道新闻
按钮,Media
组件便会接收并显示。
总结
- Mitt 是一个事件总线(EventBus),可用于平行组件间传数据;
- 接收数据方使用
emitter.on
方法订阅事件,待事件发生时接收对应数据; - 接收数据方在卸载时需要主动调用
emitter.off
方法取消事件订阅; - 发送数据方使用
emitter.emit
方法发布事件。