如何使用 TypeScript 解析 Vue.js 中的注入实例

jus*_*yoo 5 dependency-injection typescript vue.js

根据官方文档看来,只要我们停留在基于对象的结构上,我们就可以使用依赖注入功能。

这是我的问题。我正在使用 TypeScript 来实现这个目标(基于类)。我将Inversify用作 IoC 容器。我最初的想法是这样的:

DependencyConfig.ts

import { Container } from "inversify";
import "reflect-metadata";
import Warrior from "./interfaces/Warrior";
import { Ninja } from "./models/Warrior";

let container = new Container();

container.bind<Warrior>(Symbol("Warrior")).to(Ninja);

export default container;
Run Code Online (Sandbox Code Playgroud)

App.ts

import container from "./DependencyConfig";

@Component({
  name: "App",
  provide: container
})
export default class App extends Vue {
}
Run Code Online (Sandbox Code Playgroud)

当我检查浏览器的开发控制台时,我能够看到container已设置为该_provided字段。这是Hello.ts的子组件App.ts

Hello.ts

@Component({
  name: "Hello",
  inject: [ "container" ]
})
export default class Hello extends Vue {
  created (): void {
    console.log(this);
  }
}
Run Code Online (Sandbox Code Playgroud)

由于App.ts可以访问Hello.tsthrough vue-router,它没有注册Hello.ts为子组件。我期待注入的容器应该出现在_injected或类似的东西上。但是,我找不到它。我将inject属性值从更改为"container"{ "container": Symbol("Container") }但仍然找不到。

服务定位器

使用服务定位器而不是provide/inject一对可以很好地工作:

// App.ts
@Component({
  name: "App"
})
export default class App extends Vue {
}

// Hello.ts
import container from "./DependencyConfig";

@Component({
  name: "Hello"
})
export default class Hello extends Vue {
  created (): void {
    var ninja = container.get<Ninja>(Symbol("Warrior"));
    console.log(ninja.name);
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,我想避免在这里使用服务定位器模式。使用这provide/inject对进行依赖注入时我错过了什么吗?

jus*_*yoo 5

我找到了解决方案。如果我们使用vue-class-componentand vue-property-decorator,我们可以实现这个目标——使用provide/inject对。这是我的代码片段:

// App.vue
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import SERVICE_IDENTIFIER from "./models/Identifiers";
import container from "./configs/DependencyConfigs";

@Component({
  name: "App",
  // Provides IoC container at the top level of VueComponent
  provide: {
    [SERVICE_IDENTIFIER.CONTAINER]: container
  }
})
export default class App extends Vue {
}
</script>
Run Code Online (Sandbox Code Playgroud)

在最顶层的 Vue 组件中App.vue,我们提供了container实例,以便其所有子组件都可以使用它。这是它的子组件之一Ninja.vue

// Ninja.vue
<script lang="ts">
import Vue from "vue";

// Imports both Component and Inject decorators from vue-property-decorator,
// instead of vue-class-component
import { Component, Inject } from "vue-property-decorator";

import { Container } from "inversify";

import SERVICE_IDENTIFIER from "../models/Identifiers";
import { Ninja as _Ninja } from "../models/Warrior";

@Component({
  name: "Ninja"
})
export default class Ninja extends Vue {
  public warrior: string;
  public weapon: string;

  // IoC container provided from App.ts is injected here
  @Inject(SERVICE_IDENTIFIER.CONTAINER)
  private _container: Container;

  private _ninja: _Ninja;

  created (): void {
    this._ninja = this._container.get<_Ninja>(SERVICE_IDENTIFIER.WARRIOR);
    this.warrior = this._ninja.name;
    this.weapon = this._ninja.weapon.name;
  }
}
</script>
Run Code Online (Sandbox Code Playgroud)

子组件使用@Inject(Symbol)装饰器containerApp.vue.

我用英语韩语写了一篇关于这个的博客文章。

HTH