【问题标题】:How to resolve injected instances in Vue.js using TypeScript如何使用 TypeScript 在 Vue.js 中解析注入的实例
【发布时间】:2017-08-11 04:01:49
【问题描述】:

根据official document,似乎只要我们保持基于对象的结构,我们就可以使用依赖注入功能。

这是我的问题。我正在使用 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;

App.ts

import container from "./DependencyConfig";

@Component({
  name: "App",
  provide: container
})
export default class App extends Vue {
}

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

Hello.ts

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

由于App.ts 可以通过vue-router 访问Hello.ts,它没有将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);
  }
}

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

【问题讨论】:

    标签: typescript dependency-injection vue.js


    【解决方案1】:

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

    // 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>
    

    在最顶层的 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>
    

    子组件使用@Inject(Symbol) 装饰器从App.vue 解析注入的container 实例。

    我在EnglishKorean 都写了一篇关于这个的博文。

    HTH

    【讨论】:

    • 您实际上是在描述服务定位器模式,请参阅martinfowler.com/articles/injection.html#UsingAServiceLocator。所以这不是一个解决方案。
    • @FrankLiepert 实际上,它是一种服务定位器模式。 SL 是另一种类型的 DI。 AFAIK,SL 是在 Vue.js 中实现 DI 的唯一方法。
    猜你喜欢
    • 1970-01-01
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    • 1970-01-01
    • 2021-05-10
    • 2018-07-13
    相关资源
    最近更新 更多