文章目录
- 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) => void
on: (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: List
constructor() {
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 = Mit
app.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()