文章目录
- Provide 和 Inject
- 兄弟组件通信Event Bus
- Mitt库
Provide 和 Inject
provide
可以在祖先组件中指定我们想要提供给后代组件----子、孙等组件的数据或方法,而在任何后代组件中,我们都可以使用 inject
来接收 provide
提供的数据或方法。
父组件
<template><div class="App"><button>我是App</button><A></A></div>
</template><script setup lang='ts'>
import { provide, ref,readonly } from 'vue'
import A from './components/A.vue'
let flag = ref<number>(1)
provide('flag', flag) 父组件传递provide('flag', readonly(flag)) 这种传递方式子组件是无法修改数据的
</script><style>
.App {background: blue;color: #fff;
}
</style>
子组件
<template><div style="background-color: green;">我是B<button @click="change">change falg</button><div>{{ flag }}</div></div>
</template><script setup lang='ts'>
import { inject, Ref, ref } from 'vue'const flag = inject<Ref<number>>('flag', ref(1)) 子组件接收
const change = () => {flag.value = 2 子组件可以修改传递的值
}
</script><style>
</style>
注意:你如果传递普通的值是不具有响应式的 需要通过ref reactive 添加响应式。
如果不让后代组件修改数据可以在传递数据的时候加上readonly限制。
兄弟组件通信Event Bus
这个原理其实是运用了JS设计模式之发布订阅模式,通过一个中间件来处理。
type BusClass<T> = {emit: (name: T) => voidon: (name: T, callback: Function) => void
}
type BusParams = string | number | symbol
type List = {[key: BusParams]: Array<Function>
}
class Bus<T extends BusParams> implements BusClass<T> {list: Listconstructor() {this.list = {}}emit(name: T, ...args: Array<any>) {let eventName: Array<Function> = this.list[name]eventName.forEach(ev => {ev.apply(this, args)})}on(name: T, callback: Function) {let fn: Array<Function> = this.list[name] || [];fn.push(callback)this.list[name] = fn}
}export default new Bus<number>()
Mitt库
Mitt是一个体积极小的第三方消息发布/订阅式JavaScript库,React、Vue均可以使用。
安装
npm install --save mitt
main.ts 初始化
import { createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt'const Mit = mitt()//TypeScript注册
// 由于必须要拓展ComponentCustomProperties类型才能获得类型提示
declare module "vue" {export interface ComponentCustomProperties {$Bus: typeof Mit}
}const app = createApp(App)//Vue3挂载全局API
app.config.globalProperties.$Bus = Mitapp.mount('#app')
A组件派发(emit)
<template><div><h1>我是A</h1><button @click="emit1">emit1</button><button @click="emit2">emit2</button></div>
</template><script setup lang='ts'>
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance();
const emit1 = () => {instance?.proxy?.$Bus.emit('on-num', 100)
}
const emit2 = () => {instance?.proxy?.$Bus.emit('*****', 500)
}
</script><style>
</style>
B组件监听(on)
<template><div><h1>我是B</h1></div>
</template><script setup lang='ts'>
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
instance?.proxy?.$Bus.on('on-num', (num) => {console.log(num,'===========>B')
})
</script><style>
</style>
监听一个
instance?.proxy?.$Bus.on('on-num', (num) => {console.log(num,'===========>B')
})监听所有
instance?.proxy?.$Bus.on('*',(type,num)=>{console.log(type,num,'===========>B')
})移除监听事件
instance?.proxy?.$Bus.on('on-num',Fn)//listen
instance?.proxy?.$Bus.off('on-num',Fn)//unListen清空所有监听
instance?.proxy?.$Bus.all.clear()