依赖注入的目的是便于上层组件提供数据的便捷,主要出现在多层级间进行数据传递。Inject 作用在获取数据的组件,同时还要由 Provide 作用在上层组件为其提供数据。
在类组件中可以通过 @Inject
装饰器来描述一个类属性为注入的数据,在 03类组件详解中 有讲到可以通过 @Component
装饰器的选项 provide
来在上层组件进行数据提供,现在应该是获取上层组件提供的数据了。
在顶层组件的 @Component
装饰器增加选项 provide
,provide 为一个函数是为了接收一组对象,且对象中的指定数据可能为计算属性,因为只有计算属性快照发生变化后,下层组件中获取的数据才会发生变化:
vue
<script lang="ts">
import { computed } from 'vue';
import CardWapper from './components/CardWapper.vue';
import { Component, Vue } from 'vue-facing-decorator';
@Component({
components: {
CardWapper,
},
provide() {
return {
title: computed(() => this.title),
footers: this.footers,
}
}
})
export default class App extends Vue {
title = '相册集';
footers = [
{
name: 'copy',
link: 'http://www.baidu.com',
},
{
name: 'jump',
link: 'https://juejin.cn',
},
];
update() {
this.title = '相册集' + Date.now();
}
}
</script>
<template>
<div>
<button @click="update">更新标题</button>
<CardWapper></CardWapper>
</div>
</template>
<script lang="ts">
import { computed } from 'vue';
import CardWapper from './components/CardWapper.vue';
import { Component, Vue } from 'vue-facing-decorator';
@Component({
components: {
CardWapper,
},
provide() {
return {
title: computed(() => this.title),
footers: this.footers,
}
}
})
export default class App extends Vue {
title = '相册集';
footers = [
{
name: 'copy',
link: 'http://www.baidu.com',
},
{
name: 'jump',
link: 'https://juejin.cn',
},
];
update() {
this.title = '相册集' + Date.now();
}
}
</script>
<template>
<div>
<button @click="update">更新标题</button>
<CardWapper></CardWapper>
</div>
</template>
在 CardWapper
中添加 Card
组件,不做多余的配置:
vue
<script lang="ts">
import Card from './Card.vue';
import { Component, Vue } from 'vue-facing-decorator';
@Component({
name: 'CardWapper',
components: {
Card,
},
})
export default class CardWapper extends Vue {}
</script>
<template>
<Card></Card>
</template>
<script lang="ts">
import Card from './Card.vue';
import { Component, Vue } from 'vue-facing-decorator';
@Component({
name: 'CardWapper',
components: {
Card,
},
})
export default class CardWapper extends Vue {}
</script>
<template>
<Card></Card>
</template>
在 Card
组件中使用 @Inject
获取已经注入的数据,from
参数与提供时指定的一致,如果 @Inject 所描述的类属性与提供时的名称一致可忽略 from
参数:
vue
<script lang="ts">
import { Component, Inject, Vue } from 'vue-facing-decorator';
@Component({
name: 'Card',
})
export default class Card extends Vue {
@Inject({
from: "title",
})
title!: string;
@Inject({
from: "cover",
default:
'https://www.bing.com/th?id=OHR.PandiZucchero_ZH-CN9833521922_1920x1080.webp',
})
cover!: string;
@Inject({
from: "footers",
})
footers!: any;
}
</script>
<template>
<div class="container">
<div class="title">{{ title }}</div>
<img :src="cover" />
<div class="footer">
<button v-for="footer in footers">{{ footer.name }}</button>
</div>
</div>
</template>
<style scoped>
.container {
text-align: left;
width: 240px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
margin: 20px;
transition: 0.2s;
}
.container:hover {
transform: scale(1.01);
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.container .title {
font-size: 18px;
font-weight: 600;
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
.container img {
width: 240px;
height: 135px;
border-radius: 5px;
margin-top: 10px;
}
.container .footer {
display: flex;
gap: 10px;
justify-content: right;
}
</style>
<script lang="ts">
import { Component, Inject, Vue } from 'vue-facing-decorator';
@Component({
name: 'Card',
})
export default class Card extends Vue {
@Inject({
from: "title",
})
title!: string;
@Inject({
from: "cover",
default:
'https://www.bing.com/th?id=OHR.PandiZucchero_ZH-CN9833521922_1920x1080.webp',
})
cover!: string;
@Inject({
from: "footers",
})
footers!: any;
}
</script>
<template>
<div class="container">
<div class="title">{{ title }}</div>
<img :src="cover" />
<div class="footer">
<button v-for="footer in footers">{{ footer.name }}</button>
</div>
</div>
</template>
<style scoped>
.container {
text-align: left;
width: 240px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
margin: 20px;
transition: 0.2s;
}
.container:hover {
transform: scale(1.01);
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.container .title {
font-size: 18px;
font-weight: 600;
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
.container img {
width: 240px;
height: 135px;
border-radius: 5px;
margin-top: 10px;
}
.container .footer {
display: flex;
gap: 10px;
justify-content: right;
}
</style>
[^注]: 到 3.0.0 版本为止,案例中发现在下层组件获取的数据会被增加多余的双引号,在 3.0.1 增加的 @Provide 装饰器我似乎还是没明白如何实现响应式。