也算是经典面试题的一部分了,对于父子间的通讯很多时候的使用我都是限于 props
/$emit
来处理,或者 Vuex
/EventBus
这种方式,很少会用到 Provide
/Inject
来处理。其实这是一个很实用的跨级组件间通讯的方式。
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。
看文档中关于这对API的解释就可以看到,向其所有后代 注入一个依赖,所以在跨级组件间通讯,或者 单父多子组件间通讯就会很方便了。
简单的使用可以查看官方文档中的示例,我就不举例了,因为使用起来真的很简单。
最直白的(但是错误的)可以理解为 props
的强化版本,暴露一个可以无视子组件的嵌套层级属性来进行注入。
在使用的过程中主要会遇到的问题基本上是以下两种:
#1 注入一个方法给后代组件使用:
注入一个方法给后代组件使用,只需要在 provide
返回的对象中声明想要暴露的方法即可。
// 父级组件提供 'fn'
export default {
// 如果想要提供当前组件中的一些属性和方法,需要使用 return 一个对象来指定 this 的指向.
// 不然会提示 `Cannot read properties of undefined` 或者 `xxx is not defined`。
provide() {
return {
fn: this.customFn
}
},
methods:{
customFn(){
// ....
}
}
// ...
}
// 子组件注入 'fn'
export default {
inject: ['fn'],
// ...
}
#2 注入一个可响应的对象给后代组件使用:
其实也不复杂,查看官网的提示就可以知道应该如何操作了。
提示:
provide
和inject
绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的property
还是可响应的。
注入一个被监听的对象即可,比如说在 data
或者 computed
中声明的 对象、对象数组。
// 父级组件提供被监听的对象
export default {
provide() {
return {
testObj: this.testObj,
testObjArray: this.testObjArray
}
},
data(){
return {
// 对象
testObj:{ a:'aa', b:'bb' },
// 对象数组
testObjArray: [{ c:'ccc' }, { d:'ddd' }]
}
},
mounted(){
// 子组件初始化后修改变量值
this.$nextTick(()=>{
this.changeData()
})
},
methods:{
// 修改变量值
changeData(){
this.testObj.a = 'Lorem Ipsum'
this.$set(this.testObjArray, 0, { c: 'new Value'})
}
}
}
// 子组件注入并监听
export default {
inject: ['testObj','testObjArray'],
watch:{
testObj:{
handler(val){
console.log('child watcher: testObj changed', val);
},
deep:true
},
testObjArray(val){
console.log('child watcher: testObjArray changed', val);
}
}
}
😣 遇到问题
#1 有些人可能会问为啥我修改了被监听的对象,但是没有触发子组件的监听事件?
一看问出这个问题的就是没有好好读文档,建议重新读一遍关于 watch
的文档。
其实通过 deep
或者传入回调数组监听某一个用到的属性值即就行了,我上方的示例中也写了 watch
监听对象的方式,多仔细看看好吧。
文档
provide/inject - API — Vue.js 2.x
Provide/Inject - 组合式 API | Vue.js 3.x