一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
那些兄弟,父子,爷孙。。。的沟通方式,详细请见下文
Provide/Inject(依赖注入)
- 介绍:
多用于层级较多的组件通讯中,当多层级组件嵌套时,最外层级的组件需要向最里面的组件传值时,可以用到Provide/Inject,这样既不会影响这条链路上的其他组件,最里面的子组件也可以顺利拿到最外层组件传出来数据。
- 使用:
父组件通过
Provide将数据传出,Provide第一个参数时键名,第二个参数为键值,键值需要使用reactive或ref包裹将其变为响应式数据。随后子组件通过Inject接收,但是子组件再修改值时会报错,所以需要在获取时候给一个默认值。
代码示例如下:
父组件:
<template>
<div class="home">
Home
<button>Home</button>
<Main></Main>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, provide } from 'vue'
import Main from './main.vue'
let mesg = ref<string>('jiang');
provide('mesg', mesg);
</script>
子组件
<template>
<div style="background:yellow;">
Main
<button @click="handleClick">bian</button>
<div>{{mesg}}</div>
</div>
</template
<script setup lang="ts">
import { inject,Ref, ref } from 'vue';
let mesg = inject<Ref<string>>('mesg', ref('jxx')) // 这里ref('jxx')默认值就是防止报错的,因为mesg.value又可能为undefined
const handleClick = () => {
mesg.value = 'hah'
}
</script>
兄弟组件传值
兄弟组件是如何进行通话的,可以直接通话吗?还是要借助“爸爸”,反正,我是不想第三方替我传话,太麻烦,相信兄弟之间肯定有些不想被他人知道的小秘密吧😉。下面就来说道说道公开谈话与私密谈话的不同方式吧~
- 第一种方法,通过一个父组件作为桥梁,为两个子组件传话,实现兄弟组件的传值。不过,这种传值方式有些麻烦并不是很推荐。(不想让“爸爸”作为传话筒,那就试试第二种方法吧~)
- 第二种方法,通过
eventBus,下面是一个博主实现的简易的bus
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>()
使用:
在需要派发的组件通过emit将数据派发出去,然后再需要接收的组件通过on进行接收。
home组件:
<template>
<div class="home">
<button @click="send1">发送</button>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, provide } from 'vue'
import Bus from '../Bus'
let flag = false;
const send1 = () => {
flag = !flag
Bus.emit('handleClick', flag)
}
</script>
main组件:
<template>
<div style="background:yellow;">
{{Flag}}
</div>
</template>
<script setup lang="ts">
import { inject,Ref, ref } from 'vue';
import Bus from '../Bus'
let Flag = ref(false)
Bus.on('handleClick', (flag:boolean) => {
Flag.value = flag;
})
</script>
App.vue
<template>
<Home />
<Main></Main>
</template>
<script setup lang="ts">
import Home from './views/home.vue'
import Main from './views/main.vue'
</script>
或者如果不想自己实现bus,那么这里推荐一个插件mitt,正常使用即可。
简单介绍:首先下载安装mittyarn add mitt,然后新建一个ts文件导出mitt实例即可。
import mitt from 'mitt';
export default mitt();
总结
在这里说一点题外话,Vue3并不是特别推荐全局变量,特别时针对TS的全局API,尤大也有相关说明不建议全局API在TS中使用。
在需要数据的情况下,可以在根组件通过Provide方法将数据派发出去,然后在需要的组件通过Inject去获取,或者使用EventBus和vuex来解决。当然,也只是推荐,如果一定要定义全局变量就需要用到getCurrentInstance,有兴趣的伙伴移步官网一探究竟吧~
最后,其实组件传值有很多方式,我们要注意甄别哪些是比较符合当前功能的传值方法,后面还会介绍其他组件传值方式,好啦~ 今天的学习就到这里啦~ 后续请听下回分解😏