inject
一、组合式
inject()
注入一个由祖先组件或整个应用 (通过 app.provide()
) 提供的值。与注册生命周期钩子的 API
类似,inject()
必须在组件的 setup()
阶段同步调用。
1.1 语法
const value = inject('key');
const value = inject('key', 'default value'); // 注入基础数据
const value = inject('key', ()=> 'default value'); // 注入引用数据
const value = inject('key', ()=> {} , false); // 注入函数
-
key
: 注入的key
。Vue
会遍历父组件链,通过匹配key
来确定所提供的值。如果父组件链上多个组件对同一个key
提供了值,那么离得更近的组件将会“覆盖”链上更远的组件所提供的值。如果没有能通过key
匹配到值,inject()
将返回undefined
,除非提供了一个默认值。 -
默认值
: 可选的,即在没有匹配到key
时使用的默认值。它也可以是一个工厂函数,用来返回某些创建起来比较复杂的值。如果默认值本身就是一个函数,那么你必须将false
作为第三个参数传入,表明这个函数就是默认值,而不是一个工厂函数。
1.2 通信
provide
和 inject
如果绑定的是基础数据, 那么是非响应的。 provide
和 inject
如果绑定的是响应式的对象,那么对象的 property
是可响应的
- 父组件
- 子组件
<template>
<div>
{{ a }}
<button @click="changeA(a+1)">父组件按钮</button>
<Child></Child>
</div>
</template>
<script setup lang="ts">
import { provide, reactive, ref } from "vue";
import Child from "./Child.vue"
const a = ref(0);
const changeA = (value: number)=>{
a.value = value;
}
const b = reactive({
a,
changeA,
});
provide('a',a.value);
provide('b',b);
</script>
<template>
<div>
{{ a }}
{{ b.a }}
<button @click="b.changeA(10)">子组件按钮</button>
</div>
</template>
<script setup lang="ts">
import { inject } from 'vue';
const a = inject('a')
const b = inject('b');
</script>
二、选项式
inject
用于声明要通过从上层提供方匹配并注入进当前组件的属性。请注意,注入绑定并非响应式的。这是有意为之的一个设计。如果要注入的值是一个响应式对象,那么这个对象上的属性将会保留响应性。
2.1 语法
inject
选项应该是以下两种之一:
-
一个字符串数组
-
一个对象: 其
key
名就是在当前组件中的本地绑定名称,而它的值应该是以下两种之一:-
匹配可用注入的
key
(string
或者Symbol
) -
一个对象:
-
from
: 一个key
(string
或者Symbol
),用于匹配可用的注入 -
default
: 用作候补值。和props
的默认值类似,如果它是一个对象,那么应该使用一个工厂函数来创建,以避免多个组件共享同一个对象。如果没有供给相匹配的属性、也没有提供默认值,那么注入的属性将为undefined
。
-
-
inject: ['a','b','state'],
inject: {
a: {
from: 'a',
default: 'XXX'
},
b: {
from: 'b',
default: 'XXX'
},
state:{
from: 'state',
default: ()=>{
return XXX
}
}
}
2.2 通信
provide
和 inject
如果绑定的是基础数据, 那么是非响应的。 provide
和 inject
如果绑定的是响应式的对象,那么对象的 property
是可响应的
- 父组件
- 子组件
<template>
<div>
<HelloWorld></HelloWorld>
<button @click="addNum">App 组件 增加 State.Num</button>
<button @click="addListItem">App 组件 增加 State.List</button>
</div>
</template>
<script>
import HelloWorld from "./HelloWorld.vue";
export default {
name: "App",
components: {
HelloWorld,
},
data() {
return {
state: {
num: 0,
list: [],
},
};
},
provide() {
return {
state: this.state,
addNum: this.addNum,
addListItem: this.addListItem
};
},
methods: {
addNum() {
this.state.num = this.state.num + 1;
},
addListItem(){
const item = this.state.num;
this.state.list.push(item)
}
},
};
</script>
<template>
<div>
{{ this.value.num }}
<ul>
<li :key="index" v-for="(item,index) in value.list">{{ item }}</li>
</ul>
<button @click="addListItem">HelloWorld 组件 增加 State.List</button>
</div>
</template>
<script>
export default {
inject: {
value: {
from: "state",
default: () => {
return { num: 0, list: [] };
},
},
addNum: {
from: "addNum"
},
addListItem: {
from : "addListItem"
}
},
};
</script>