💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、豆包、星火、月之暗面及文生图、文生视频 广告
# 提供/注入 > 本章节需要掌握组件基础 我们经常使用`props`从父组件传递数据到子组件。相像一下你有一个多级嵌套的组件,你需要传递一个数据到底层的组件,你需要一级级往下传递,这样操作是比较繁琐的。 在这些场景下,我们使用`provide`和`inject`对。父组件可以注入所有子组件一个数据,而不用关心这个组件到底有多少层级结构。这个功能分成两部分共同完成:父组件使用`provide`选项注入数据,而子组件有一个`inject`选项可以开始使用数据。 ![](https://img.kancloud.cn/60/12/6012be0c65f6075af542ebf469a73f95_578x454.png) 例如我们有个嵌套组件层级像这样: ~~~ Root └─ TodoList ├─ TodoItem └─ TodoListFooter ├─ ClearTodosButton └─ TodoListStatistics ~~~ 如果我们想传递`todo-items`长度到`TodoListStatistics`,需要层级传递:`TodoList`->`TodoListFooter`->`TodoListStatistics`。使用provide/inject,我们可以直接这么干 : ~~~ const app = Vue.createApp({}) app.component('todo-list', { data() { return { todos: ['Feed a cat', 'Buy tickets'] } }, provide: { user: 'John Doe' }, template: ` <div> {{ todos.length }} <!-- rest of the template --> </div> ` }) app.component('todo-list-statistics', { inject: ['user'], created() { console.log(`Injected property: ${this.user}`) // > Injected property: John Doe } }) ~~~ 但是我们想传递组件实例属性时却不会工作: ~~~ app.component('todo-list', { data() { return { todos: ['Feed a cat', 'Buy tickets'] } }, provide: { todoLength: this.todos.length // 这会报错`Cannot read property 'length' of undefined` }, template: ` ... ` }) ~~~ 如果想访问组件实例属性,我们需要将`provide`转换为函数并返回一个对象: ~~~ app.component('todo-list', { data() { return { todos: ['Feed a cat', 'Buy tickets'] } }, provide() { return { todoLength: this.todos.length } }, template: ` ... ` }) ~~~ 这可以允许我们更安全的持续开发组件,而不必担心可能会更改或移除某些子组件依赖的内容。这些组件间的接口定义是清晰的,就像`props`。 事实上,你可以把这种依赖注入相像成“长props”,除了: * 父组件并不需要知道具体是哪个层级组件使用它提供的数据。 * 子组件并不需要知道这个数据到底是谁提供来的。 ## 响应式工作 上面这个例子,如果我们更改了todos的列表,这个改变并不会传递到提供的`todsLength`属性,因为默认情况下`provide`并不是响应式的。我们可以传递`ref`或`reactive`对象给`provide`来改变这个行为。这个示例,我们响应式的改变顶级组件的属性值,我们需要为`provide`的`todoLength`分配一个响应式的API`computed`: ~~~ app.component('todo-list', { // ... provide() { return { todoLength: Vue.computed(() => this.todos.length) } } }) app.component('todo-list-statistics', { inject: ['todoLength'], created() { console.log(`Injected property: ${this.todoLength.value}`) // > Injected property: 5 } }) ~~~ 这样,任何`todos.length`的改变都会正确的反应到`todoLength`的组件中。 关于`computed`属性可以阅读[计算属性及监听器](https://www.kancloud.cn/zhouyu629/vue3x/2175138)了解更多,响应式`provide/inject`参考[响应式API章节](https://v3.vuejs.org/guide/composition-api-provide-inject.html#reactivity)。