vue3中使用第三方插件mitt实现任意组件通讯

vue3中使用第三方插件mitt实现任意组件通讯

组件通讯是vue3组合式开发的核心之一,现在我在写代码时,一个组件的代码超过了200行,基本都会拆分组件。组件拆分后,组件之间的通讯就很重要,总结了一下,目前有这么几种组件通讯类型:

  • 父子通讯,这是最常见的通讯方式,父传子子传父,就是父组件向子组件传值,直接使用自定义属性就可以了,父组件中定义属性,子组件中使用defineProps接受父组件传递过来的值,不过需要注意传值响应式的问题;子传父采用自定义事件,在子组件中,使用defineEmits自定义事件,并在执行某个操作时,把这个自定义事件发射出去,同时把想传递的值带上,父组件中使用@自定义事件接收值,并进行相应的操作。父子通讯与vue2并无太大的差异,只是写法不一样而已,个人的博客之前也有记录,参考vue组件之间的数据共享
  • 祖孙组件通讯,使用provide/reject实现,参考vue3使用provide&inject实现祖孙组件通讯,这是一种更复杂的组件传值的方式,比较好用,但是它只适用于上级组件向下级组件传值,不能反过来,我在写vue3时,极少用到
  • 兄弟组件通讯。这是日常开发最常遇到的,尤其是vue3中,一个父组件,然后多个子组件,子组件与子组件之间要通讯,实现起来有很多种方式,我最喜欢用的是pinia/vuex,在vue3中pinia的写法更加简约好用,所以vue3中我几乎放弃了vuex。但是有个问题,pinia作为全局数据共享工具,如果仅实现两个兄弟组件之间的通讯,那么用起来总感觉比较浪费资源。后来学习到了一种更好操作的写法,就是使用mitt第三方插件。在vue2中,mitt是官方的工具,其实就是bus事件总线,vue3移除了,尚不知道是什么原因。这篇博客主要介绍一下怎么使用mitt实现兄弟组件传值

一、安装及封装导出

安装。作为第三方插件,先安装再使用

shell 复制代码
npm i mitt -D

导出

新建个文件mitt.js,填入以下代码,即封装了一个mitt方法

javascript 复制代码
// 第一种是创建一个工具js,不如说mitt.js,哪个组件要用到就引入该文件就好了。
import mitt from 'mitt'
const emitter = mitt()
export default emitter

二、组件A发射指令

组件中引入mitt,并通过事件发射指令

javascript 复制代码
import mitt from '@/utils/mitt'
const emitter = mitt
const mittName = ['showOverall', 'showDriverAge', 'showAge', 'showOffences', 'showHelmetBelt', 'showOccRequire', 'showCumulativeScore']

const btns = ref([
    { title: '总体情况', type: 'warning' },
    { title: '驾龄', type: 'success' },
    { title: '年龄', type: 'success' },
    { title: '违法', type: 'success' },
    { title: '一盔一带', type: 'success' },
    { title: '从业资格', type: 'success' },
    { title: '累计计分', type: 'success' },
])
const chooseTag = i => {
    btns.value.forEach(item => item.type = 'success')
    btns.value[i].type = btns.value[i].type === 'warning' ? 'success' : 'warning'
    emitter.emit(mittName[i])
}

上面的代码挺复杂,业务逻辑是我点击某个按钮,就显示对应的页面,按钮组如下:

每次点击一个按钮,就修改这个按钮的类型,同时发射这个按钮对应的指令名

三、组件B接收指令

组件B作为组件A的兄弟(广义的兄弟,五湖四海皆兄弟的意思)组件,当A发出指令后,它的其他兄弟都可以接收这个指令

javascript 复制代码
<template>
    <Overall v-if="showOverall"></Overall>
    <DriverAge v-if="showDriverAge"></DriverAge>
    <Age v-if="showAge"></Age>
    <Offences v-if="showOffences"></Offences>
    <HelmetBelt v-if="showHelmetBelt"></HelmetBelt>
    <OccRequire v-if="showOccRequire"></OccRequire>
    <CumulativeScore v-if="showCumulativeScore"></CumulativeScore>
</template>

<script setup>
import { ref } from 'vue'
import Overall from './tags/Overall.vue'
import DriverAge from './tags/DriverAge.vue';
import Age from './tags/Age.vue'
import Offences from './tags/Offences.vue'
import HelmetBelt from './tags/HelmetBelt.vue'
import OccRequire from './tags/OccRequire.vue'
import CumulativeScore from './tags/CumulativeScore.vue'

import mitt from '@/utils/mitt'
const emitter = mitt

const showOverall = ref(true)
const showDriverAge = ref(false)
const showAge = ref(false)
const showOffences = ref(false)
const showHelmetBelt = ref(false)
const showOccRequire = ref(false)
const showCumulativeScore = ref(false)

const events = [
    { emitterName: 'showOverall', showState: showOverall },
    { emitterName: 'showDriverAge', showState: showDriverAge },
    { emitterName: 'showAge', showState: showAge },
    { emitterName: 'showOffences', showState: showOffences },
    { emitterName: 'showHelmetBelt', showState: showHelmetBelt },
    { emitterName: 'showOccRequire', showState: showOccRequire },
    { emitterName: 'showCumulativeScore', showState: showCumulativeScore },

]

events.forEach(item => {
    emitter.on(item.emitterName, () => {
        // ChatGPT提供的代码,牛逼
        events.forEach(i => {
            i.showState.value = (i === item);
        });
    })
})



</script>

<style lang="scss" scoped>
.el-header {
    // background-color: #333;
    box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
    display: flex;
}
</style>

同样,上面接收指令的代码也挺复杂的,还借助了chatAI的力量才实现的

解释一下吧,就是我在一个页面上写了很多个不同的组件,通过v-if来控制是否显示这个组件,而v-if则是通过组件A的按钮点击事件来确定的

javascript 复制代码
const events = [
    { emitterName: 'showOverall', showState: showOverall },
    { emitterName: 'showDriverAge', showState: showDriverAge },
    { emitterName: 'showAge', showState: showAge },
    { emitterName: 'showOffences', showState: showOffences },
    { emitterName: 'showHelmetBelt', showState: showHelmetBelt },
    { emitterName: 'showOccRequire', showState: showOccRequire },
    { emitterName: 'showCumulativeScore', showState: showCumulativeScore },
]

events是定义的一个事件数组,emitterName是组件A发过来的事件名,showState则是显示状态

javascript 复制代码
events.forEach(item => {
    emitter.on(item.emitterName, () => {
        // ChatGPT提供的代码,牛逼
        events.forEach(i => {
            i.showState.value = (i === item);
        });
    })
})

遍历训练events数组,监听里面的每个指令,当监听到了之后,就把它的showState置为true,只是多了个环节,判断当前的指令和当前点击的按钮是否相同,巧妙的实现了页面的点击响应,主要是能省不少代码。。。

俗事太多,很长一段时间没写代码,甚是怀恋,也不知道自己还能坚持几年🤡

相关推荐
环境栈笔记10 分钟前
指纹浏览器检查代理失败怎么排查?先分清代理、网络和检测服务
前端·人工智能·后端·自动化
ShineWinsu15 分钟前
对于HTML:HTML常见标签的解析—下
前端·css·面试·html·标签·表单·emmet
恋猫de小郭16 分钟前
Kotlin 2.5 的 Companion 改造,对 KMP 的重要升级
android·前端·flutter
前端双越老师30 分钟前
程序员 1v1 访谈系列第二期:很焦虑但又不知道干啥
前端·ai编程·全栈
雪芽蓝域zzs37 分钟前
Webstorm打开uniapp uvue文件报红处理方案
vue.js
广州华水科技43 分钟前
北斗形变监测传感器在大坝安全监测中的应用与优势分析
前端
孔令飞1 小时前
如何学习Go
前端
HUIBUR科技1 小时前
AI 中枢,面向企业场景构建的 AI 智能体
前端·数据库·人工智能
怕浪猫1 小时前
给AI配一台电脑,开源版Muse来了,OpenMuse赶紧去二次开发吧
javascript·面试·github
随便写个软件1 小时前
【新版本】EasyExplorer资源管理器 3.12.0——地址栏重要更新
运维·服务器·前端·everything·资源管理器