通常从父组件向子组件传递数据时,用的最多的就是Props。如果有这种场景:有一些深层嵌套的组件。如果使用Props就很复杂了,例如以下结构的嵌套组件:
Root
└─ TodoList
├─ TodoItem
└─ TodoListFooter
├─ ClearTodosButton
└─ TodoListStatistics
需要从TodoList 传递到 TodoListStatistics,如果使用Props,就只能TodoList —> TodoListFooter —> TodoListStatistics 逐层传递。
对于这种情况,可以使用一对provide
和inject
。无论组件层次结构有多深,父组件都可以向所有子组件一键传递数据。
// 爷爷组件
export default {
name: 'todo-list',
data() {
return {
todos: ['吃🍚', '看🎬']
}
},
provide: {
todo: '打球'
}
}
// 孙子组件
export default {
name: 'todo-list-statistics',
inject: ['todo'],
created() {
console.log(this.todo) // 打球
}
}
这种写法无法传递组件实例prototype,以下写法将会报错
export default {
name: 'todo-list',
data() {
return {
todos: ['吃🍚', '看🎬']
}
},
provide: {
todo: this.todos[0] // Cannot read property 0 of undefined
}
}
要访问组件实例 property,需将provide
作为一个函数,返回一个对象,就像data选项
export default {
name: 'todo-list',
data() {
return {
todos: ['吃🍚', '看🎬']
}
},
provide() {
return {
todo: this.todos[0]
}
}
}
以上例子中,如果todos变化了,子组件无法响应其变化,因为provide/inject
不是响应式的。可以为 provide
的 todo 分配一个 computed:
provide() {
return {
todo: Vue.computed(() => this.todos[0])
}
}
在vue2中,可以使用Object.defineProperty
使provide
具有响应性
export default {
data() {
return {
todos: [],
}
},
provide() {
const rootData = {}
Object.defineProperty(rootData, "todos", {
enumerable: true,
get: () => this.todos,
})
return {
rootData
}
}
}
子组件中就可以通过this.rootData.todos
拿到父组件的todos