Web-Angular的Services服务与Injectables依赖

Services服务

        服务是一种打包应用程序基本操作的方式。它们旨在提供可重用和模块化的代码,用于应用程序的深层处理。相比之下,组件(见上文)应该更关注用户视图。应用程序的逻辑包含在服务中。请注意,Angular系统不强制执行此概念,你需要自己将逻辑移到应用程序的服务中。
服务是普通的Typescript代码,它们没有任何Angular装饰器。但是,还有一些特殊类型的服务带有Angular代码装饰器,例如我们将在下一节中讨论的注入器。
        到目前为止,我们使用了非常简单的应用程序示例,其中应用程序逻辑很简单,可以很容易地包含在组件中。Angular服务应该包含详细的逻辑,并为一个或多个组件以及应用程序中的其他服务提供接口。普通的服务只是一个Typescript类。例如,下面的服务有一个非常简单的接口,它返回一个随机的颜色字符串。你可能能够想象出这个接口如何从远程服务器检索颜色字符串时作为服务器交互。这有点棘手,我们会单独讨论服务器交互。
        让我们实现一个简单的服务,它提供一个返回代表颜色的伪随机字符串的方法。以下代码实现了服务(请注意这是纯Typescript,没有任何Angular代码)。

export class ColourService {
  private static colours = ["red", "green", "blue", "black", "pink"];
  public getColour(): string {
    return ColourService.colours[Math.floor(Math.random() * ColourService.colours.length)];
  }
}

        这段代码从颜色字符串数组中选择一个随机字符串。
        我们可以实现一个使用此服务的组件,如下所示。

import { Component } from '@angular/core';
import { ColourService } from './colour.service';

@Component({
  selector: 'app-root',
  template: `<h1>Random Colours</h1>
             <p>My colour is:
             <span [style.color]="colour">{
   
   {colour}}</span>
             </p>
             <button (click)="change()">New Colour</button>
            `
})
export class AppComponent {
  colour: string;
  private colourServer: ColourService;
  
  constructor() {
    this.colourServer = new ColourService();
    this.colour = this.colourServer.getColour();
  }
  
  change() {
    this.colour = this.colourServer.getColour();
  }
}

        需要注意以下几点:

  1. 我们使用Typescript的import语句导入了ColourService类型。
  2. 主要的组件类在其构造函数中创建了一个ColourService类的新实例,并选择了初始的随机值。这是不好的Angular实践,下面将进行解释。
  3. 使用事件处理程序,在用户每次点击按钮时更改颜色。请注意将[style.color] CSS样式选择器的赋值用于更改文本的颜色。记住这里应该使用美式发音的颜色。
    当选择红色字符串时,实际应用程序如下所示。

        如上所述,创建服务类的新实例不是良好的实践。这引起了一些问题,包括在组件之间的可重用性、确定哪个组件初始化它以及其他组件如何知道它是否已初始化。为了解决这些潜在的编程问题,Angular引入了可注入组件,接下来我们将看一下这方面的内容。

Dependency Injection依赖注入

        依赖注入(Dependency Injection)是 Angular 中用于控制服务行为的方式。您可能已经意识到,我们在应用程序中需要设置一个服务来访问远程网站。例如,Web 服务由谁启动、如何管理 Web 服务(错误、响应速度慢等)以及其他服务相关的问题都由 Angular 运行时处理。它通过使用修饰器 @Injectable 来装饰我们的 TypeScript 服务,并向 Angular 运行时系统提供一些钩子来实现这一点。

        我们可以通过添加 Angular 修饰器来使上一节中的服务可注入,代码如下:

import { Injectable } from '@angular/core';

@Injectable()
export class ColourService {
  private static colours = ["red", "green", "blue", "black", "pink"];
  
  public getColour(): string {
    return ColourService.colours[Math.floor(Math.random() * ColourService.colours.length)];
  }
}

对于服务代码,这里的唯一更改是导入 Angular 修饰器并将其插入到服务代码之前的行上。该修饰器没有参数,但会插入到类定义中。

现在,在定义一个可注入服务后,我们需要以 Angular 的方式使用它,以便 Angular 可以管理该服务。在我们的例子中,我们想要在主要应用组件中使用可注入的服务。Angular 通过查看组件构造函数参数来识别服务(构造函数是 Angular 自动初始化服务的地方)。我们可以为我们的组件添加以下构造函数:

export class AppComponent {
  colour: string;
  
  constructor(private colourServer: ColourService) {
    this.colour = this.colourServer.getColour();
  }
  
  change() {
    this.colour = this.colourServer.getColour();
  }
}

        这里对 AppComponent 代码的更改如下:

  1. 构造函数现在将私有的服务变量作为构造函数参数,而不是在类中以单独的属性存在。
  2. 构造函数不再创建 ColourService 对象,这个工作现在由 Angular 运行时处理。
  3. 我们仍然需要在构造函数中进行初始化,以便显示第一个颜色。

        使用这个可注入的服务还需要进行最后一步操作。Angular 使用一个声明来跟踪服务提供者的所有提供者。在我们的例子中,我们可以通过将以下内容添加到 @Component 修饰器的参数中,将 appComponent 组件作为提供者:

providers: [ColourService]

        我们还可以将可注入的服务附加到模块定义上。@NgModule 修饰器将包含上述 providers 属性,并且模块类的构造函数可以像组件中那样使用。在未来的实验室会话中,我们将看到更完整的示例。

        Angular 还提供了“钩子”,允许我们在可注入服务的生命周期的不同阶段执行代码。在上面的示例中,我们在构造函数中调用了服务的 getColour() 方法。虽然在我们的示例中这看起来合理,但是请想象一下,如果我们的服务是连接到远程服务器的,调用将在连接完成后才会完成。这对于我们的组件来说是个问题,因为它负责更新显示区域,所以用户会在访问服务器时注意到显示的部分内容。换句话说,服务初始化会阻碍应用界面的流畅显示。Angular 允许我们延迟执行代码,直到可注入服务初始化完成,同时允许组件视图完成。

        OnInit 钩子是一种将代码打包以在服务完全初始化后执行的方法。它通过在组件中添加一个方法来工作,该方法包含代码,Angular 运行时会在服务初始化后记得调用该方法。

        我们的应用程序的完整代码现在如下所示:

import { Component, OnInit } from '@angular/core';
import { ColourService } from './colour.service';

@Component({
  selector: 'app-root',
  template: `
    <h1>Random Colours</h1>
    <p>My colour is:
      <span [style.color]="colour">{
   
   {colour}}</span>
    </p>
    <button (click)="change()">New Colour</button>
  `,
  providers: [ColourService]
})
export class AppComponent implements OnInit {
  colour: string;

  constructor(private colourServer: ColourService) {}

  ngOnInit(): void {
    this.colour = this.colourServer.getColour();
  }

  change() {
    this.colour = this.colourServer.getColour();
  }
}

        请注意以下有关此代码的内容:

  1. 我们现在从 Angular 核心模块导入 OnInit。
  2. 钩子是 ngOnInit 方法,现在包含在视图中初始化颜色的代码。
  3. 构造函数体现在为空。通常情况下,我们应该尽量在构造函数中减少代码量,以便 Angular 能够尽快更新视图。

        除了 OnInit 钩子之外,还有其他几个钩子。一些示例有:

  • ngOnChanges - 在组件接收输入属性时被调用。
  • ngAfterViewInit - 在组件视图初始化之后调用一次。
  • ngOnDestroy - 在 Angular 销毁组件或其他 Angular 对象之前调用。这允许进行清理,例如释放对象以节省空间或处理关闭连接等工作。

        它们的使用方式与上面显示的 ngOnInit 相同。

猜你喜欢

转载自blog.csdn.net/qq_54813250/article/details/133816338