Vue3开发极简入门(17):无关联组件间通信之mitt
前面介绍的,父子、爷孙组件通信方式,要想解决子子、孙孙间通信,两个无关联组件的通信还是太麻烦的。
mitt可适用于任意组件间的通信。
对于后端的开发同学来说,mitt可以类比Kafka,一个基于发布/订阅模式的消息队列。
安装mitt:
npm i mitt
创建一个全局的emitter文件,src/utils/emitter.ts:
import mitt,{type Emitter} from "mitt";
type Events={
sayToSon1:string,
sayToSon2?:string,
sayToAll:string
}
const emitter: Emitter<Events> = mitt<Events>();
// 不同Emitter的写法
// const emitter = mitt<Events>();
export default emitter
- Events就是所有Topic的集合。
- sayToAll就是Topic。后面的string代表此事件回调函数要传入的参数类型。string、number、对象都可以。?代表参数可选。
很多时候搜索资料,网上给出的多是js的写法,超简单:
import mitt from 'mitt';
const emitter = mitt();
export default emitter;
但是,TypeScript对类型要求严格,本文还是用TS的写法。
写一个父组件,两个子组件。父组件没什么用,就是引入一下两个子组件,代码就不放了。
两个子组件代码基本一致。
Son1.vue:
<template>
<div class="son1">
<h1>子1组件</h1>
消息:<div v-html="msgToMe"></div>
<br>
<button @click="sayToSon2">向Son2说话</button>
<button @click="sayToAll">向所有人说话</button>
</div>
</template>
<script lang='ts' setup name='Son1'>
import { onBeforeUnmount, onMounted, ref } from 'vue';
import emitter from '@/utils/emitter';
const msgToMe = ref("")
function sayToSon2() {
emitter.emit('sayToSon2', "Son1向Son2说:" + Math.random())
}
function sayToAll() {
emitter.emit('sayToAll', "Son1向所有人说:" + Math.random())
}
const sayToSon1 = (msg: string) => {
msgToMe.value = msgToMe.value + "<br/>" + msg
}
onMounted(() => {
emitter.on('sayToSon1', sayToSon1)
emitter.on('sayToAll', sayToSon1)
})
onBeforeUnmount(() => {
emitter.all.clear
})
</script>
<style scoped>
.son1 {
background-color: silver;
padding: 10px;
margin-top: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
width: 80%;
margin: auto;
}
</style>
Son2.vue:
<template>
<div class="son2">
<h1>子2组件</h1>
消息:<div v-html="msgToMe"></div>
<br>
<button @click="sayToSon1">向Son1说话</button>
<button @click="sayToAll">向所有人说话</button>
</div>
</template>
<script lang='ts' setup name='Son2'>
import { onBeforeUnmount, onMounted, ref } from 'vue';
import emitter from '@/utils/emitter';
const msgToMe = ref("")
function sayToSon1() {
emitter.emit('sayToSon1', "Son2向Son1说:" + Math.random())
}
function sayToAll() {
emitter.emit('sayToAll', "Son2向所有人说:" + Math.random())
}
const sayToSon2 = (msg?: string) => {
msgToMe.value = msgToMe.value + "<br/>" + msg
}
onMounted(() => {
emitter.on('sayToSon2', sayToSon2)
emitter.on('sayToAll', sayToSon2)
})
onBeforeUnmount(() => {
emitter.off('sayToSon2')
emitter.off('sayToAll')
})
</script>
<style scoped>
.son2 {
background-color: skyblue;
padding: 10px;
margin-top: 10px;
box-shadow: 0 0 10px black;
border-radius: 10px;
width: 80%;
margin: auto;
}
</style>
注意:
- on是订阅事件,一般在页面加载的时候进行。emitter.on(Topic名,回调函数)。
- off是取消订阅事件,all.clear是取消订阅所有事件。要在页面卸载的时候取消订阅,防止内存泄露。