我有一个问题,当我们尝试将非 Angular “事物”注入组件时,Angular 如何管理它们的注入。
所有可注入的东西在Angular中都被称为provider。每个提供者都以对信息的形式呈现。
Angular 需要首先确定一个提供者,然后它需要给出值。 标识符是满足===表达式的JavaScript值,值是任何JavaScript类型(即对象、数组、字符串、数字、函数)。
我们可以使用类构造函数作为标识符,因为它满足=== 表达式。
例如;
class MyService {}
// assume MyService is provided via a NgModule somewhere
const x: Type<MyService> = MyService;
console.log(x === MyService); // prints true
console.log(injector.get(x)); // prints MyService instance
console.log(injector.get(MyService)); // prints same MyService instance as above
当我们提供一个类构造函数作为提供者的标识符时,它被称为服务。使用依赖注入的类是最常见的做法,我们称它们为服务是因为它更容易理解。
那么,我的问题是 Modal 实例是如何注入到我们的 AppComponent 构造函数中的?
它之所以有效,是因为您在类的顶部添加了一个 @Component({...}) 装饰器。
TypeScript 将在首次声明类原型时调用类装饰器。装饰器是一个 JavaScript 函数,它接收原型作为参数。 Angular 在这个阶段检查具有构造函数的原型。使用对构造函数的引用 Angular 可以查看有多少参数及其类型。
请记住上面我展示了如何使用类构造函数从注入器中获取实例。 @Component() 装饰器对构造函数执行相同的操作以获取 modal 的实例。它修改原始构造函数,获取可注入值并将值作为参数传递。这一切都是可能的,因为我们在创建 Angular 项目时默认启用了 TypeScript 中的特殊功能。
或者,一个更通用的问题是,Angular 如何“提供”这些非服务类/函数的实例?
Angular 中有不同类型的提供者。有些是静态值,有些是工厂函数,还有类提供者。如果Modal 类型是一个类提供者,那么Angular 将在第一次它被注入时创建一个新实例。然后,该值会被 injector 实例缓存并重新使用。
我的第二个问题是,这些“原型”类型的注入(我们尝试注入的新组件的新实例?)
Angular 创建了一个注入器的树。当一个 provider 被获取时,注入器搜索 tree 直到找到该 provider 的注入器。根据提供者的类型(见上文),会读取一个 value。如果是类类型,则该注入器会创建并缓存一个新实例。
如果没有提供该类型的注入器,则会引发类型未知的注入错误。
Modal 是从哪里来的?
Modal 是一个abstract 类,但它们仍然有一个唯一 构造函数,可以用作标识符提供者。
您正在使用的库具有为Modal 类提供功能的插件。例如; bootstrap 插件有一个为Modal 类声明provider 的模块。您可以在源代码中看到,他们使用自定义类提供程序将默认类替换为 不同 类。
https://github.com/shlomiassaf/ngx-modialog/blob/44f16f73a5418ac3c41f4ebbc3ed58538a1adea5/projects/plugins/bootstrap/src/lib/bootstrap.module.ts#L17