一、参考

  1. vue3 eventBus
  2. npm mitt

二、问题描述

Vue3 没有像Vue2那样创建一个Vue实例作为事件传递的对象( 参考Vue2.x eventBus全局管理事件的“订阅/发布”),因此需要借助 mitt 插件来实现

三、开发案例

  1. 目录结构

请添加图片描述

  1. 定义 eventBus.ts 文件, 保证所有的引用都是同一个对象(单例)
import mitt, { Emitter } from 'mitt'

export const $Bus: Emitter = mitt()
export default $Bus

  1. main.ts 文件中引用eventBus.ts,保证事件订阅是单例
mport { createApp } from 'vue'
import { Emitter } from 'mitt' // 用于 EventBus
import App from './App.vue'
const app = createApp(App)

/* *********** 引入 vue-router 4 ************ */
import router from './router'
app.use(router) // 加载路由

/* *********** 引入 mitt ************ */
import $Bus from '@/utils/eventBus'
// 定义监听事件
$Bus.on('foo', (params) => {
  console.log('params', params)
});
// 触发事件
$Bus.emit('foo', 42);
// 定义到全局
app.config.globalProperties.$Bus = $Bus
  1. 父组件监听事件
<template>
  <busComp class=""></busComp>
  <div>我是父组件 pageBus</div>
</template>

<!-- <script setup lang="ts">
// 这里vue组件的后缀要不从全了,如果省略,虽然vite 能够识别并正确展示,但是ts无法识别,导致编译器一直提示找不到模块
import busComp from '@/pages/vue3Advance/comp/busComp.vue';
import { getCurrentInstance, onMounted, onBeforeUnmount } from 'vue';
const instance = getCurrentInstance();

function handleBus(val: any) {
  console.log('handleBus', val);
}

onMounted(() => {
  instance?.proxy?.$Bus.on('on-btn-click', handleBus);
})

onBeforeUnmount(() => {
  console.log('beforeUnmount')
  instance?.proxy?.$Bus.off('on-btn-click', handleBus);
});
</script> -->

<script lang="ts">
import { defineComponent, ref, reactive, computed } from 'vue'
import busComp from '@/pages/vue3Advance/comp/busComp.vue'

export default defineComponent({
  components: {
    busComp
  },
  mounted: function () {
    console.log('mounted')
    this.$Bus.on('on-btn-click',this.handleBus)
  },
  beforeUnmount: function () {
    console.log('beforeUnmount')
    this.$Bus.off('on-btn-click',this.handleBus)
  },
  methods: {
    handleBus (val: any) {
      console.log('handleBus', val)
    }
  }
})
</script>

<style scoped lang="scss"></style>
  1. 子组件busComp.vue触发事件
<template>
  <div class="">
    <el-button type="primary" @click="emitEvent">触发mitt定义的bus</el-button>
  </div>
</template>

<script setup lang="ts">
import  {getCurrentInstance} from 'vue'
const instance= getCurrentInstance() // 获取组件实例,相当于配置选项的this

function emitEvent () {
  instance?.proxy?.$Bus.emit('on-btn-click','我是mitt bus触发的事件')
}

</script>

<style scoped lang="scss">
</style>

typescript 解析 instance?.proxy?.$Bus出错?

  1. Vue3定义实例的声明类型文件,参考官网扩展全局属性

请添加图片描述

  1. 定义 tsconfig.json 指明声明文件的位置
{
  "compilerOptions": {
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "paths": {
      "@/*": ["./src/*"] // 设置别名路径
    },  
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "strict": true,
    "jsx": "preserve",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["ESNext", "DOM"],
    "skipLibCheck": true,
    "types": ["./src/types/*.d.ts", "vite/client", "unplugin-icons/types/vue"],
    "noEmit": true
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/router/dynamicAddRoutes.bad.ts"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

分别在 compilerOptions.typesinclude 两个属性下面引入的自定义的声明文件

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐