Skip to content

兄弟组件传参

  1. 子组件A通过defineEmits给父组件派发一个事件,并传递一个参数flag,代码如下:
vue
<template>
    <div>
        <button @click="emitB">派发一个事件</button>
    </div>
</template>

<script setup lang='ts'>
import { ref } from 'vue'

const emit = defineEmits(['on-click'])
let flag = false
const emitB = () => {
    flag = !flag
    emit('on-click', flag)
}
</script>
<style scoped></style>

  1. 父组件通过注册on-click事件来接收到子组件A传过来的值flag
  2. 父组件通过v-bind向子组件B传递参数Flag
vue
<template>
    <div>
        <A @on-click="getFlag"></A>
        <B :flag="Flag"></B>
    </div>
</template>

<script setup lang='ts'>
import { ref } from 'vue'
import A from './A.vue'
import B from './B.vue'
let Flag = ref(false)

const getFlag = (flag: boolean) => {
    Flag.value = flag
}
</script>
<style scoped></style>

  1. 子组件B通过defineProps接收父组件传过来的值flag
vue
<template>
    <div>
        {{ flag }}
    </div>
</template>

<script setup lang='ts'>
import { ref } from 'vue'
type Props = {
    flag: boolean
}

defineProps<Props>()
</script>
<style scoped></style>

这样当子组件A进行派发事件修改flag的值,其兄弟组件B中的flag也会改变。也就完成了兄弟组件传参。

发布-订阅模式

发布-订阅模式(Pub-Sub pattern)的事件总线(Event Bus)。它创建了一个消息系统,允许多个对象(称为订阅者)监听某个事件(称为主题),当这个事件被触发(发布)时,所有订阅了这个事件的对象都会收到通知。

代码如下:

typescript
// 发布-订阅模式
type BusClass<T> = {
    emit: (name: T) => void
    on: (name: T, callback: Function) => void
    off: (name: T, callback: Function) => void
    once: (name: T, callback: Function) => void
}

type PramsKey = string | number | symbol

type List = {
    [key: PramsKey]: Array<Function>
}

class Bus<T extends PramsKey> implements BusClass<T> {
    list: List
    constructor() {
        this.list = {}
    }
    // 调用所有订阅了这个事件的回调函数,并传入参数
    emit(name: T, ...args: Array<any>) {
        let eventName: Array<Function> = this.list[name] || []
        eventName.forEach(fn => {
            fn.apply(this, args)
        })
    }
    // 将回调函数添加到这个事件的订阅者列表中
    on(name: T, callback: Function) {
        let fn: Array<Function> = this.list[name] || []
        fn.push(callback)
        this.list[name] = fn
    }
    // 从这个事件的订阅者列表中移除这个回调函数
    off(name: T, callback: Function) {
        let fn: Array<Function> = this.list[name] || []
        this.list[name] = fn.filter(f => {
            f !== callback
        })
    }
    // wrappedCallback会在被触发时调用原始的回调函数,并使用 off 方法取消订阅这个事件
    once(name: T, callback: Function) {
        const wrappedCallback = (...args: Array<any>) => {
            callback.apply(this, args)
            this.off(name, wrappedCallback)
        }
        this.on(name, wrappedCallback)
    }
}

export default new Bus<string>()

这时候,父组件只需要引入A和B两个子组件,B组件通过调用Bus类的on方法注册回调函数:

vue
<script setup lang='ts'>
import { ref } from 'vue'
import bus from '../../utils/Bus.ts'

let flag = ref(false)

bus.on('on-click',(Flag:boolean)=>{
    flag.value=Flag
})
</script>

A组件通过调用Bus类的emit方法调用相应的回调函数:

vue
<script setup lang='ts'>
import { ref } from 'vue'
import bus from '../../utils/Bus.ts'

const emit = defineEmits(['on-click'])
let flag = false
const emitB = () => {
    flag = !flag
    bus.emit('on-click', flag)
}
</script>

这种方式不需要通过父组件即可完成兄弟组件传参。

也可以引入mitt实现兄弟传参

Released under the MIT License.