先从git上扒来一段话介绍一下mitt这个库:
Mitt是一个小巧的JavaScript发布-订阅库,用于在应用程序中实现事件监听和触发。
它只有70行代码,并支持ES模块、CommonJS和UMD等多种模块化规范。使用Mitt,您可以轻松地将消息传递给订阅者,从而实现组件之间的通信和功能扩展。该库非常灵活且易于使用,可帮助您优化项目的结构和性能。
在项目开发中经常会遇到组件之间互相通信,如父子兄弟之间。之前一直用$emit绑定方法,很麻烦而且还有局限性。然而mitt提供的发布订阅模式,可以全局监听并且使用简洁易懂。
介绍一下它的几个方法:
on:订阅一个事件。
off:根据给定的名称,取消订阅事件。
emit:触发订阅事件的方法。
下面进入实战:
1.先安装一下mitt
npm install -S mitt
2. 在src下创建plugins目录,并新建mybus.js,然后按照如下进行实例化导出
import mitt from 'mitt'
export default mitt()
3. 在进行发布订阅的组件中导入mitt,主要就是send方法中的
mitt.emit("fun", {
data:"data"
});
第一个参数是发布事件名称,第二个参数是要发布的数据。
解释一下我为什么这里用了setTimeout。因为有的业务场景,目标组件是不显示的,此时v-if=false,所以目标组件就无法监听订阅事件。
所以这里分开执行,当我需要发布的时候,先把组件显示出来,然后再进行事件发布。
<template><h2>组件A</h2><button @click="send">发送消息</button><B v-if="show"></B>
</template>
import {reactive, toRefs, watch, getCurrentInstance, onMounted} from "vue"
import mitt from "@/plugins/mybus"
import B from '@/views/b.vue'
export default {name: "a",components:{B},setup(props, {emit}) {const state = reactive({show:false})const send = ()=>{state.show=true;setTimeout(function(){mitt.emit("fun", {data:"data"});})}onMounted(() => {})return {...toRefs(state),send}}}
4. 目标组件进行订阅,这里的监听主要就是
mitt.on('fun',(data)=>{
console.log("B接收到A的数据:",data)
});
使用mitt的on方法来订阅事件,第一个参数是事件名称,第二个参数是回调方法,回调参数就是发布的数据
import {reactive, toRefs, watch, getCurrentInstance, onMounted} from "vue"
import mitt from "@/plugins/mybus"
export default {name: "b",setup(props, {emit}) {onMounted(() => {mitt.on('fun',(data)=>{console.log("B接收到A的数据:",data)});})}}
我想大部分同志都是为了解决问题才看到的这篇文章,为了不占用感情,所以把原理解析放到了最后
可以看下源码
function mitt(all) {// 声明一个Map类型,作为整体事件处理中心all = all || new Map();return {all,on (type, handler) {// 先获取是否有对应事件的处理函数数组let handlers = all.get(type);if (handlers) {// 将新注册的函数推送到对应时间的函数数组中handlers.push(handler);}else {// 创建一个对应 type 的函数数组all.set(type, [handler]);}},off (type, handler) {// 从map中取出所有的对应的函数数组let handlers = all.get(type);if (handlers) {// 如果存在hanlder,进行筛选后,从数组中删除。// 如果不存在直接清空当前事件所有的处理函数if (handler) {handlers.splice(handlers.indexOf(handler) >>> 0, 1);}else {all.set(type, []);}}},emit (type, evt) {let handlers = all.get(type);// 按照取出的函数数组遍历循环执行if (handlers) {handlers.slice().map((handler) => {handler(evt);});}// 如果注册了 "*" 的事件,执行它handlers = all.get('*');if (handlers) {handlers.slice().map((handler) => {handler(type, evt);});}}};
}
exports.default = mitt;
其实核心思想就是用一个map来储存事件,订阅的时候根据key来找到对应的方法。