首页 > web前端 > js教程 > Angular 2组件和提供商:类,工厂和价值观

Angular 2组件和提供商:类,工厂和价值观

尊渡假赌尊渡假赌尊渡假赌
发布: 2025-02-15 12:07:12
原创
592 人浏览过

Angular 2 Components and Providers: Classes, Factories & Values

核心要点

  • Angular 2 组件能够使用提供者 (providers),提供者是一组可注入的对象,组件可以使用它们。提供者是 Angular 2 依赖注入 (DI) 系统的基础。
  • 提供者可分为三种类型:类提供者、工厂提供者和值提供者。类提供者生成类的实例,工厂提供者生成指定函数的返回值,值提供者直接返回其值。
  • Angular 2 的 DI 系统允许注册类、函数或值(称为提供者),解决提供者之间的依赖关系,使提供者的结果可在代码中使用,并维护注入器的层次结构。
  • Angular 的注入器只创建一次类提供者的实例,并将其缓存,只要使用相同的提供者,后续每次注入都会收到相同的实例。此功能使您可以灵活地控制任何一个提供者生成的结果,以及我们是否使用单个实例或多个实例。
  • Angular 2 允许使用与实际提供者关联的键(称为“令牌”)注册提供者。此功能对于单元测试很有用,在单元测试中,可以替换一个不会进行服务器调用的模拟类,而无需更改组件代码。

前文探讨了如何使用 @Input@Output 注解将数据传入和传出组件。本文将介绍 Angular 2 组件的另一个基本方面——它们使用 提供者 的能力。

您可能在组件配置属性列表中看到过“提供者”,并且您可能意识到它们允许您定义一组可用于组件的可注入对象。这很好,但当然会引出一个问题,“什么是提供者?”

回答这个问题需要深入探讨 Angular 2 的依赖注入 (DI) 系统。我们可能会在以后的博文中专门介绍 DI,但 Pascal Precht 的一系列文章对此进行了很好的介绍,从这里开始:https://www.php.cn/link/f7f3bfce09a3008d185e1775549ec2d2 DI 和 Angular 2 的 DI 系统(如 Pascal 的文章中所述),但简而言之,DI 系统负责:

  • 注册类、函数或值。在依赖注入的上下文中,这些项目被称为“提供者”,因为它们会产生结果。例如,类用于提供或产生实例。(有关提供者类型的更多详细信息,请参见下文。)
  • 解决提供者之间的依赖关系——例如,如果一个提供者需要另一个提供者。
  • 当我们请求提供者结果时,使提供者的结果可在代码中使用。此过程(使提供者结果可用于代码块)称为“注入它”。注入提供者结果的代码逻辑上称为“注入器”。
  • 维护注入器的层次结构,以便如果组件请求其注入器中不可用的提供者的提供者结果,DI 将向上搜索注入器的层次结构。

在之前的文章中,我们包含了一个图表,显示组件形成以根组件开头的层次结构。让我们补充该图表以包含注入器及其注册的资源(提供者):

Angular 2 Components and Providers: Classes, Factories & Values

图 1:每个组件都有自己的注入器,用于注册提供者。注入器创建子注入器,对提供者的请求从本地注入器开始,并向上搜索注入器层次结构。

从上面我们可以看出,虽然组件形成了一个向下定向图,但它们相关的注入器具有双向关系:父注入器创建子注入器(向下),当请求提供者时,如果组件自己的注入器中找不到请求的提供者,Angular 2 将向上搜索父注入器(向上)。这意味着较低级别具有相同标识符的提供者将遮盖(隐藏)较高级别具有相同名称的提供者。

什么是提供者?

那么,注入器在每个级别注册的这些“提供者”是什么呢?实际上很简单:提供者是 Angular 用于提供(产生、生成)我们想要使用的资源或 JavaScript“事物”:

  • 类提供者生成/提供类的实例。
  • 工厂提供者生成/提供运行指定函数时返回的内容。
  • 值提供者不需要像前两者那样采取操作来提供结果,它只返回其值。

不幸的是,术语“提供者”有时既指类、函数或值,也指提供者产生的事物——类实例、函数的返回值或返回值。

让我们看看如何通过使用 MyClass(一个简单的类,将生成我们想要在应用程序中使用的实例)创建类提供者来向组件添加提供者。

Angular 2 Components and Providers: Classes, Factories & Values

图 2:具有四个属性的简单类。(代码屏幕截图来自 Visual Studio Code)

好了,这就是类。现在让我们指示 Angular 使用它注册类提供者,以便我们可以要求依赖注入系统提供一个实例供我们在代码中使用。我们将创建一个组件 ProvDemo_01.ts,它将用作应用程序的根组件。我们在 bootstrap.ts 中加载此组件并启动我们的应用程序:

Angular 2 Components and Providers: Classes, Factories & Values

图 3:启动应用程序的 bootstrap.ts 文件,它实例化根组件。

如果上面的内容没有意义,请查看我们之前的文章,该文章介绍了构建简单的 Angular 2 应用程序的过程。我们的根组件称为 ProvDemo,存储库包含几个不同版本的该组件。您可以通过更新上面导入 ProvDemo 的行来更改显示的版本。我们的根组件的第一个版本如下所示:

Angular 2 Components and Providers: Classes, Factories & Values

图 4:导入 MyClassCompDemo,将其添加到 providers 数组中,并在构造函数参数中将其用作类型。

向此组件添加 MyClass 提供者很简单:

  • 导入 MyClass
  • 将其添加到 @Componentproviders 属性
  • 向构造函数添加类型为“MyClass”的参数

在幕后,当 Angular 实例化组件时,DI 系统会为组件创建一个注入器,该注入器注册 MyClass 提供者。然后,Angular 会看到在构造函数的参数列表中指定的 MyClass 类型,并查找新注册的 MyClass 提供者,并使用它来生成一个实例,然后将其分配给“myClass”(初始小写“m”)。

查找 MyClass 提供者和生成要分配给“myClass”的实例的过程都是 Angular 完成的。它利用 TypeScript 语法来了解要搜索的类型,但 Angular 的注入器负责查找和返回 MyClass 实例。

鉴于上述情况,您可能会得出结论,Angular 会获取“providers”数组中的类列表,并创建一个简单的注册表来检索该类。但是,为了提高灵活性,存在一个细微的调整。需要“调整”的一个主要原因是帮助我们编写组件的单元测试,这些组件具有我们不想在测试环境中使用的提供者。对于 MyClass,没有太多理由不使用真实的东西,但是如果 MyClass 调用服务器来检索数据,我们可能不想或无法在测试环境中这样做。为了解决这个问题,我们需要能够在 ProvDemo 中替换不会进行服务器调用的模拟 MyClass

我们如何进行替换?我们是否需要遍历所有代码并将每个 MyClass 引用更改为 MyClassMock?这效率不高,并且是编写测试的糟糕模式。

我们需要在不更改 ProvDemo 组件代码的情况下替换提供者实现。为了实现这一点,当 Angular 注册提供者时,它会设置一个映射,以将键(称为“令牌”)与实际提供者相关联。在上面的示例中,令牌和提供者是同一事物:MyClass。将 MyClass 添加到 @Component 装饰器中的 providers 属性是以下内容的简写:

<code>providers: [ provide(MyClass, {useClass: MyClass} ]</code>
登录后复制
登录后复制
登录后复制

这意味着“使用 MyClass 作为令牌(键)来查找提供者,并将提供者设置为 MyClass,以便当我们请求提供者时,依赖注入系统会返回 MyClass 实例”。我们大多数人都习惯于将键视为数字或字符串。但在这种情况下,令牌(键)是类本身。我们也可以使用字符串作为令牌来注册提供者,如下所示:

<code>providers: [ provide("aStringNameForMyClass", {useClass: MyClass} ]</code>
登录后复制
登录后复制
登录后复制

那么,这如何帮助我们进行测试呢?这意味着在测试环境中,我们可以覆盖提供者注册,有效地执行以下操作:

<code>provide(MyClass, {useClass: MyClassMock})
</code>
登录后复制

这会将令牌(键)MyClass 与类提供者 MyClassMock 关联起来。当我们的代码要求 DI 系统在测试中注入 MyClass 时,我们会得到 MyClassMock 的实例,它可以伪造数据调用。最终效果是所有代码保持不变,我们不必担心单元测试是否会调用在测试环境中可能不存在的服务器。

注入非类提供者

在上面,我们通过编写以下代码将类提供者实例注入到构造函数中:

<code>constructor( myClass: MyClass ) {...}
</code>
登录后复制

TypeScript 允许我们指定 myClass 参数需要是 MyClass 类型,而 DI 系统会完成工作,为我们提供 MyClass 实例。

但是,如果我们使用字符串令牌而不是类,我们如何告诉 Angular 注入我们的提供者结果呢?让我们编辑 bootstrap.ts 文件以添加新的值提供者并使用字符串令牌注册它。请记住,值提供者是一种返回与令牌关联的值的提供者类型。在上面的示例中,我们告诉 Angular 通过添加到 @Componentproviders 属性来注册提供者,但我们也可以通过将它们传递到引导函数中来注册提供者(可以将相同的内容添加到 providers 属性):

Angular 2 Components and Providers: Classes, Factories & Values

图 5:添加了值提供者的 bootstrap.ts

在这里,我们通过调用 provide 函数并传入字符串令牌(“SECURITY_KEY”)和一个对象来添加提供者,该对象指定我们想要创建一个值提供者以及提供者本身——在本例中是一个简单值。现在,我们想将值提供者生成的值注入到我们的构造函数中,但这行不通……

<code>providers: [ provide(MyClass, {useClass: MyClass} ]</code>
登录后复制
登录后复制
登录后复制

这是因为“SECURITY_KEY”不是类型。为了使能够注入具有非类令牌的提供者成为可能,Angular 为我们提供了 @Inject 参数装饰器。与所有其他装饰器一样,我们需要导入它,然后我们使用它来告诉 Angular 注入与我们的字符串令牌关联的提供者。为此,我们调整 create ProvDemo_02.ts

Angular 2 Components and Providers: Classes, Factories & Values

图 6:导入“Inject”装饰器并使用它来注入使用字符串令牌标识的值提供者。

我们可以使用相同的语法来注入 MyClass 提供者:

<code>providers: [ provide("aStringNameForMyClass", {useClass: MyClass} ]</code>
登录后复制
登录后复制
登录后复制

好了,我们已经了解了如何注册和使用提供者,但让我们进一步了解提供者返回的内容。

提供者和单例

正如我们在上面看到的,提供者负责生成要注入的事物。类提供者会生成一个实例,然后注入该实例。但是,重要的是要理解,每次注入类提供者结果时,您都不会获得一个新实例。相反,DI 系统会生成一次实例,将其缓存,并且只要您使用相同的提供者,后续每次注入都会收到相同的实例。

最后一点很重要,因为每个组件都有自己的注入器及其自己的注册提供者。MyClass 具有设置为当前时间(以毫秒为单位)的时间属性和一个随机数,以帮助我们查看我们每次是否获得相同的实例。我们将向应用程序添加一个 ChildComp 组件。

Angular 2 Components and Providers: Classes, Factories & Values

图 7:将 MyClass 注入到构造函数中的 ChildComp

请注意,我们导入 MyClass 并使用它来设置构造函数参数列表中的类型。重要提示:导入的 MyClassChildComp 中的唯一用途是作为 DI 系统用来查找注册提供者的令牌。 因为 ChildComp 没有使用该令牌注册自己的提供者,所以 Angular 会向上查找注入器层次结构以找到一个。为了使这能够工作,我们需要将 ChildComp 添加到 ProvDemo 组件:

Angular 2 Components and Providers: Classes, Factories & Values

图 8:向模板中添加了 ChildCompProvDemo

我们导入 ChildComp,向 @Component 添加 directives 属性以告诉 ProvDemo 我们将使用 ChildComp 组件,并将 ChildComp 元素添加到模板。当应用程序运行时,控制台输出显示 ProvDemoChildComp 都收到相同的 MyClass 实例:

<code>providers: [ provide(MyClass, {useClass: MyClass} ]</code>
登录后复制
登录后复制
登录后复制

现在让我们更改 ChildComp 以向其注入器添加 MyClass 提供者:

Angular 2 Components and Providers: Classes, Factories & Values

图 9:定义了自己的 MyClass 提供者的 ParentComp

我们唯一更改的是向 @Component 注解添加 providers 属性。当然,我们可以看到创建了两个不同的 MyClass 实例:

<code>providers: [ provide("aStringNameForMyClass", {useClass: MyClass} ]</code>
登录后复制
登录后复制
登录后复制

Angular 的此功能为任何一个提供者生成的结果以及我们是否要使用单个实例或多个实例提供了很大的灵活性。例如,您可以将组件放在重复器中,以便多次生成组件。如果此重复组件注册自己的提供者,则每个组件都会获得唯一的提供者。但是,如果您只在父组件中注册提供者,则每个重复实例都会共享父组件的提供者。

总结

在本文中,我们定义了什么是提供者,并介绍了三种不同类型的提供者。然后,我们研究了如何为组件注册提供者以及如何将提供者生成的结果注入到组件中。我们还研究了 Angular 如何使用注入器层次结构来查找请求的提供者。Angular 为您提供了更多关于依赖注入系统如何工作以及在何处查找提供者的控制,但以上内容应该可以帮助您开始在 Angular 2 应用程序中创建和使用提供者。

关于 Angular 2 组件、提供者、类、工厂和值的常见问题 (FAQ)

类和工厂在 Angular 2 中有什么区别?

在 Angular 2 中,类是创建对象的蓝图。它封装了数据和操作该数据的函数。另一方面,工厂是一种用于创建对象的模式。在 Angular 2 中,工厂用于创建和配置没有明确类来表示的服务或值。工厂提供了一种根据上下文或配置生成不同类实例的方法。

组件和提供者如何在 Angular 2 中交互?

在 Angular 2 中,组件和提供者协同工作以创建动态且交互式的用户界面。组件是 Angular 应用程序的构建块,而提供者用于创建组件可以使用的服务。提供者允许组件共享数据和功能,从而更易于维护和更新应用程序。

值在 Angular 2 中的作用是什么?

Angular 2 中的值用于向应用程序的其他部分提供配置信息。它们可以注入到控制器、服务和工厂中,允许在运行时配置应用程序的这些部分。这使应用程序更灵活,也更易于测试。

如何在 Angular 2 中绑定类?

Angular 2 中的类绑定是一种动态地向元素添加和删除 CSS 类的方法。您可以将类绑定到表达式,当该表达式计算结果为 true 时,该类将添加到元素。如果表达式的计算结果为 false,则该类将被删除。这允许您创建动态且交互式的用户界面。

在 Angular 2 的上下文中,API 是什么?

在 Angular 2 的上下文中,API(应用程序编程接口)是一组用于构建和交互软件应用程序的规则和协议。Angular 2 提供了一个丰富的 API,允许开发人员使用更少的代码和精力创建复杂的应用程序。Angular 2 API 包括用于创建组件、服务、指令、管道等的特性。

如何在 Angular 2 中使用工厂?

要在 Angular 2 中使用工厂,您首先需要定义它。这是通过创建一个返回您希望工厂生成的对象的函数来完成的。然后,您可以使用 .factory 方法将此工厂与 Angular 模块注册。注册工厂后,您可以将其注入到应用程序的其他部分,例如控制器和服务。

如何在 Angular 2 中创建组件?

在 Angular 2 中创建组件涉及定义一个类并使用 @Component 装饰器对其进行装饰。@Component 装饰器告诉 Angular 该类是一个组件,并提供元数据,这些元数据确定如何在运行时处理、实例化和使用该组件。

如何在 Angular 2 中使用提供者?

Angular 2 中的提供者用于创建和向应用程序部分提供服务。要使用提供者,您首先需要将其与 Angular 模块注册。注册后,可以将提供者注入到组件、其他服务甚至其他提供者中。

如何在 Angular 2 中创建服务?

在 Angular 2 中创建服务涉及定义一个类,该类封装了服务提供的数和函数。然后,此类将使用 @Injectable 装饰器进行装饰,该装饰器告诉 Angular 该类是一个服务,可以注入到应用程序的其他部分。

如何在 Angular 2 中使用值?

Angular 2 中的值用于向应用程序的其他部分提供配置信息。要使用值,您首先需要将其与 Angular 模块注册。注册后,可以将值注入到控制器、服务和工厂中。

以上是Angular 2组件和提供商:类,工厂和价值观的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板