我们在父子关系的组件中提供数据时常常使用props,这种传递数据的方式有个确切的前提,就是两个组件的关系必须是父和子的关系。如果是祖父和孙子的关系,祖父和重孙的关系等等,数据只能通过props一层一层地往下传递,这个问题就是”prop 逐级透传“问题,显然这样是非常麻烦地,这种情况下传递数据就可以使用依赖注入了。
在Vue 3中,provide
和 inject
是用于实现组件之间依赖注入的一对新的 API。这两个 API 允许你在祖先组件中提供数据,然后在后代组件中注入这些数据,实现了一种更灵活的组件通信方式。
provide提供依赖
provide
是在祖先组件中调用的函数,用于提供数据给后代组件。它接受两个参数,第一个参数是一个键(key),用于标识提供的数据,第二个参数是要提供的数据本身。
先写一个祖先组件:
// 祖先组件C1
import { provide } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'
import C2 from './C2.js'
let template = `
<C2/>
`
export default {
components: { C2 },
setup() {
provide('mes', '我是祖先组件C1')
},
template
}
注意,上面的祖先组件引用了一个C2组件在下面注入依赖部分
应用层 Provide
除了在一个组件中提供依赖,我们还可以在整个应用层面提供依赖:
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
在应用级别提供的数据在该应用内的所有组件中都可以注入。这在你编写插件时会特别有用,因为插件一般都不会使用组件形式来提供值。
inject注入依赖
C2组件如下,要想获取祖先组件提供的依赖,可以使用inject(),inject
是在后代组件中调用的函数,用于从祖先组件中注入提供的数据。它接受一个参数,即要注入的数据的键。
// 后代组件C2
import { inject } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'
let template = `
<div>{{mes}}</div>
`
export default {
setup() {
let mes = inject('mes')
return { mes }
},
template
}
另外,inject可以提供一个默认值,如果在祖先组件中没有提供该数据,可以通过第二个参数设置一个默认值。
let mes = inject('mes', '祖先组件没有提供mes值')
使用 inject
时,数据流是单向的,即祖先组件提供数据,后代组件注入数据,而不是相反。也不能在兄弟组件间使用这种依赖注入,就好比你只能从祖先那里继承遗产,但不能在兄弟姐妹那里继承遗产。
提供和注入响应式依赖
vue官网提到“当提供 / 注入响应式的数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中。这样可以确保所提供状态的声明和变更操作都内聚在同一个组件内,使其更容易维护。当可能需要在注入方组件中更改数据。在这种情况下,推荐在供给方组件内声明并提供一个更改数据的方法函数”
祖先组件
import { ref, provide } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'
import C2 from './C2.js'
let template = `
<C2/>
`
export default {
components: { C2 },
setup() {
let mes = ref('收到请回复')
let updateMes = (message) => mes.value = message
provide('mes', {
mes,
updateMes
})
},
template
}
后代组件
import { inject } from 'https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.esm-browser.js'
let template = `
<div>{{mes}}</div>
<button v-on:click='updateMes("复")'>回复</button>
`
export default {
setup() {
let { mes, updateMes } = inject('mes')
return { mes, updateMes }
},
template
}
结语
这种依赖注入的机制使得组件之间的通信更加灵活,尤其在跨层级的组件通信时,provide
和 inject
提供了一种方便的方式。