官方文档链接

Vue2 的 Provide/inject
Vue3 的 Provide/Inject
组合式 API 中的用法

认识 provide 和 inject

provide 和 inject 是 Vue 中的一种组件间传值的解决办法
解决了深层嵌套的组件之间的传值不方便问题
先来看看这两个单词什么意思…

provide
vt. 提供; 供应; 给予; 规定

inject
vt. (给…)注射(药物等); (给…)注射(液体); (给…)添加,增加(某品质)

从直译中,就可以知道 provide 提供了数据,将这个数据沿着组件向下传递
而 inject 则是被注入了这个数据
provide 用在遥远的父组件上…而 inject 用在遥远的子组件上…

这里的遥远指的是组件之间的关系:向下跨组件传递
例如 Vue 官网给我们提供的组件结构

1
2
3
4
5
6
Root
└─ TodoList
├─ TodoItem
└─ TodoListFooter
├─ ClearTodosButton
└─ TodoListStatistics

Provide/Inject

优点和缺点

优点
方便,真的是非常方便…
两个组件离得很远,但是父组件 provide,子组件 inject,两行代码就解决了传值问题
vuex,eventbus,props 虽然都可以实现,不论逻辑上还是代码上,负担都挺不小的…

缺点
数据流向不明
这个问题就好像一个人在长江上游放了个小黄鸭,小黄鸭顺着长江向下漂流…
长江两岸有很多人,他们都能看到这个小黄鸭,也都能知道这个小黄鸭是黄色的….
可是没有人知道这只鸭鸭是谁放的

option 中使用

基础使用方法

option 即选项,vue2 中 data,watch,methods 之类的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 提供数据的组件
export default {
provide: {
searchText : '搜索内容'
}
}

// 接收数据的组件
export default {
inject: ['searchText']
}
// inject 默认值
export default {
inject: {
searchText: {
default: '搜索文字的默认值'
// 如果默认值为非原始值, 那么需要对其使用一个工厂方法
default: () => ['默', '认', '值']
}
}
}

相隔遥远的组件传值竟如此简单…

处理响应性

默认情况下,provide/inject 并不是响应式的

提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。

setup api 中使用

使用方法

setup api 和 option 差不多,只是换了个写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 提供数据--Provide
import { provide } from 'vue'
// provide(name, value)
// name (<String> 类型)
// value
// 多个provide数据就执行多个provide方法
export default {
setup() {
provide('searchText', 'search')
return {}
}
}

// 接收数据--Inject
import { inject } from 'vue'
// inject(name, default)
// name (<String> 类型)
// default (默认值)
// 多个inject数据执行多个inject方法
export default {
setup() {
const searchText = inject('seachText', '默认值')
return { searchText }
}
}

处理响应式

和 option 一样,provide 和 inject 方法默认不支持响应式
但是可以通过传入响应式数据
例如,在 provide 中传值的时候,用 ref()或 reactive()这两个响应式 api 处理一下值

1
2
3
4
5
6
7
8
import { ref } from "vue";
export default {
setup() {
const refStr = ref("search");
provide("searchText", refStr);
return {};
},
};