兄弟组件以及跨组件传参——eventBus

348 阅读1分钟

eventBus

vue3onon,off和$once 实例方法已被移除,因此我们无法像在vue2中使用 这些方法实现eventBus,不过,可以使用一个插件来提供类似的功能,mitt插件。

插件地址:www.npmjs.com/package/mit…

安装插件

pnpm install mitt -S

mitt插件提供了四个方法:

all() : 返回当前所有事件监听器的集合。

emit() : 触发一个自定义事件,并且可以携带参数

on() : 监听当前实例上的自定义事件

off() : 移除对自定义事件的监听

下面展示如何使用

配置插件

//main.ts
//使用mitt插件
import mitt from 'mitt'
//挂载全局属性
app.config.globalProperties.$eventBus = mitt()

兄弟组件之间传参

现在有组件A和组件B,在index.vue中引入两个组件同级,A和B属于兄弟组件,下面实现兄弟组件之间的传参

组件A

//A.vue
<template>
  <div class="A-container">
    <p class="name">A组件</p>
    <n-button @click="handleClick()">点击</n-button>
    <!--<AS></AS>-->
  </div>
</template>
<script lang="ts" setup>
import AS from '@/components/eventBus/AS.vue'
import { getCurrentInstance } from 'vue'
const vm = getCurrentInstance()

const handleClick = () => {
  vm?.proxy.$eventBus.emit('on-click', 1)
}
</script>
<style scoped lang="scss">
.A-container {
  height: 400px;
  width: 500px;
  background: #cacaca;
  .name {
    font-weight: 600;
    font-size: 24px;
  }
}
</style>

组件B

//B.vue
<template>
  <div class="B-container">
    <p class="name">B组件</p>
    <div class="data">{{ count }}</div>
  </div>
</template>
<script lang="ts" setup>
import { getCurrentInstance, onUnmounted, ref } from 'vue'

const vm = getCurrentInstance()
let count = ref<number>(0)
//监听自定义事件
vm?.proxy?.$eventBus.on('on-click', (num) => {
  count.value += num
})
onUnmounted(() => {
  //在组建取消挂载的时候,移除对自定义事件的监听
  vm?.proxy?.$eventBus.off('on-click')
})
</script>
<style scoped lang="scss">
.B-container {
  height: 400px;
  width: 500px;
  background: #54a29e;
  .name,
  .data {
    font-weight: 600;
    font-size: 24px;
  }
}
</style>

父组件

//index.vue
<template>
  <div class="eventBus-container">
    <p class="name">父组件</p>
    <p class="data">{{ data }}</p>
    <A></A>
    <B></B>
  </div>
</template>
<script setup lang="ts">
import { getCurrentInstance, onUnmounted, ref } from 'vue'
import A from '@/components/eventBus/A.vue'
import B from '@/components/eventBus/B.vue'
const vm = getCurrentInstance()
let data = ref(0)
//监听自定义事件
vm?.proxy?.$eventBus.on('handleIndex', (num) => {
  data.value += num
})
onUnmounted(() => {
  //移除对自定义事件的监听
  vm?.proxy?.$eventBus.off('handleIndex')
})

</script>
<style lang="scss" scoped>
.eventBus-container {
  text-align: center;
  background: aquamarine;
  padding-left: 100px;
  .name,
  .data {
    font-weight: 600;
    font-size: 24px;
  }
}
</style>

效果

1png.png

跨组件传参

子孙组件AS

//AS 组件
<template>
  <div class="AS-container">
    <p class="name">子孙组件</p>
    <n-button @click="handleClick()">点击</n-button>
  </div>
</template>
<script lang="ts" setup>
import { getCurrentInstance } from 'vue'
const vm = getCurrentInstance()

const handleClick = () => {
  vm?.proxy.$eventBus.emit('handleIndex', 1)
}
</script>
<style lang="scss" scoped>
.AS-container {
  height: 200px;
  width: 300px;
  background: palegreen;
  .name {
    font-size: 18px;
    font-weight: 600;
  }
}
</style>

组件 A

在A组件中引入AS.vue,A.vue 和 AS.vue为父子组件。

//A.vue
<template>
  <div class="A-container">
    <p class="name">A组件</p>
    <n-button @click="handleClick()">点击</n-button>
    <AS></AS>
  </div>
</template>
<script lang="ts" setup>
import AS from '@/components/eventBus/AS.vue'
import { getCurrentInstance } from 'vue'
const vm = getCurrentInstance()

const handleClick = () => {
  vm?.proxy.$eventBus.emit('on-click', 1)
}
</script>
<style scoped lang="scss">
.A-container {
  height: 400px;
  width: 500px;
  background: #cacaca;
  .name {
    font-weight: 600;
    font-size: 24px;
  }
}
</style>

父组件

父组件为index index中引入了A组件 ,index.vue 和 A.vue为父子组件; A.vue中引入了AS.vue ,

A.vue和AS.vue为父子组件, AS.vue 为index.vue的子孙组件,AS.vue传参到index.vue属于是跨组件传参

//index.vue
<template>
  <div class="eventBus-container">
    <p class="name">父组件</p>
    <p class="data">{{ data }}</p>
    <A></A>
    <B></B>
  </div>
</template>
<script setup lang="ts">
import { getCurrentInstance, onUnmounted, ref } from 'vue'
const vm = getCurrentInstance()
let data = ref(0)
//监听自定义事件
vm?.proxy?.$eventBus.on('handleIndex', (num) => {
  data.value += num
})
onUnmounted(() => {
  //移除对自定义事件的监听
  vm?.proxy?.$eventBus.off('handleIndex')
})
import A from '@/components/eventBus/A.vue'
import B from '@/components/eventBus/B.vue'
</script>
<style lang="scss" scoped>
.eventBus-container {
  text-align: center;
  background: aquamarine;
  padding-left: 100px;
  .name,
  .data {
    font-weight: 600;
    font-size: 24px;
  }
}
</style>

效果

点击子孙组件中的按钮,可以发现父组件中的数字发生了变化,说明跨组件传参成功

2.png

这是一个子孙组件向父组件传递参数的例子,父组件向子孙组件也是一样的流程,需要在父组件中使用emit提交自定义事件,在子孙组件中使用emit提交自定义事件,在子孙组件中使用on 监听事件既可。