Skip to content

依赖注入的目的是便于上层组件提供数据的便捷,主要出现在多层级间进行数据传递。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>

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>

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>

[^注]: 到 3.0.0 版本为止,案例中发现在下层组件获取的数据会被增加多余的双引号,在 3.0.1 增加的 @Provide 装饰器我似乎还是没明白如何实现响应式。