您的当前位置:首页正文

Angular6学习笔记8: 服务(Service)(1)

2024-11-25 来源:个人技术集锦

服务(Service)

继学习笔记7,可以使用主从组件,现在继续学习(服务)Service;

问题:为什么需要服务?


因为:组件不应该直接获取或保存数据,它们不应该了解是否在展示假数据。 它们应该聚焦于展示数据,而把数据访问的职责委托给某个服务。


这次将创建一个 HeroService,应用中的所有类都可以使用它来获取英雄列表。 不要使用 new 来创建此服务,而要依靠 Angular 的依赖注入机制把它注入到 HeroesComponent 的构造函数中

服务是在多个“互相不知道”的类之间共享信息的好办法。

1.创建HeroService

使用 Angular CLI 创建一个名叫 hero 的服务。

ng generate service hero
wjydeMacBook-Pro:demo wjy$ ng generate service hero
CREATE src/app/hero.service.spec.ts (362 bytes)
CREATE src/app/hero.service.ts (133 bytes)

 执行完这个命令以后,打开src/app/hero.service.ts 中生成 HeroService,

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

@Injectable({
  providedIn: 'root'
})
export class HeroService {

  constructor() { }
}

@Injectable() 服务

这个新的服务导入了 Angular 的Injectable  符号,并且给这个服务类添加了 @Injectable() 装饰器。 它把这个类标记为依赖注入系统的参与者之一。HeroService 类将会提供一个可注入的服务,并且它还可以拥有自己的待注入的依赖。 目前它还没有依赖.

@Injectable() 装饰器会接受该服务的元数据对象,就像 @Component() 对组件类的作用一样。

2.在HeroService中获取hero的数据

HeroService 可以从任何地方获取数据:Web 服务、本地存储(LocalStorage)或一个模拟的数据源。

从组件中移除数据访问逻辑,意味着将来任何时候你都可以改变目前的实现方式,而不用改动任何组件。

在HeroService中导入 Hero 和 HEROES,并写一个获取hero列表的方法:getHeroes()

import {Injectable} from '@angular/core';
import {Hero} from './hero';
import {HEROES} from './mock-heroes';

@Injectable({
  providedIn: 'root'
})
export class HeroService {

  constructor() {
  }

  getHeroes(): Hero[] {
    return HEROES;
  }
}

3.提供(provide) HeroService

在要求 Angular 把 HeroService 注入到 HeroesComponent 之前,你必须先把这个服务提供给依赖注入系统。通过注册提供商来做到这一点。提供商用来创建和交付服务,在这个例子中,它会对 HeroService 类进行实例化,以提供该服务,需要确保 HeroService 已经作为该服务的提供商进行过注册。 你要用一个注入器注册它。注入器就是一个对象,负责在需要时选取和注入该提供商。默认情况下,Angular CLI 命令 ng generate service 会通过给 @ 装饰器添加元数据的形式,为该服务把提供商注册到根注入器上。如果你看看 HeroService 紧前面的 @() 语句定义,就会发现  元数据的值是 'root',当你在顶层提供该服务时,Angular 就会为 HeroService 创建一个单一的、共享的实例,并把它注入到任何想要它的类上。 在 @ 元数据中注册该提供商,还能让 Angular 可以通过移除那些完全没有用过的服务,来进行优化。

注意:如果需要,可以在不同的层次上注册提供商 —— 在 HeroesComponent 中、在 AppComponent 中,或在 AppModule 中。 比如,可以通过附加 --module=app 参数来告诉 CLI 要自动在模块级提供该服务。

ng generate service hero --module=app

4.修改 HeroesComponent

打开 HeroesComponent 类文件。

删除 HEROES 的导入语句,因为你以后不会再用它了。 转而导入 HeroService,把 heroes 属性的定义改为一句简单的声明。

import {Component, OnInit} from '@angular/core';
import {Hero} from '../hero';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  hero: Hero = {
    id: 1,
    name: 'Windstorm',
  };
  heroes: Hero[];
  selectedHero: Hero;

  constructor() {
  }

  ngOnInit() {
  }

  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
}

5.注入 HeroService

往构造函数中添加一个私有的 heroService,其类型为 HeroService

constructor(private heroService: HeroService) { }

添加 getHeroes()

getHeroes(): void {
  this.heroes = this.heroService.getHeroes();
}

6.在 ngOnInit 中调用getHeroes()

a.在构造方法中调用(不推荐)

在构造函数调用:getHeroes();

constructor(private heroService: HeroService) {
    this.getHeroes();
  }

这样也会达到之前应用的效果,如图

b.在 ngOnInit 生命周期钩子中调用

在ngOnInit 调用:getHeroes();

ngOnInit() {
    this.getHeroes();
  }

这样也会达到之前应用的效果,如图

两者的比较:

让构造函数保持简单,只做初始化操作,比如把构造函数的参数赋值给属性。 构造函数不应该做任何事它肯定不能调用某个函数来向远端服务(比如真实的数据服务)发起 HTTP 请求。

而是选择在 ngOnInit 生命周期钩子中调用 getHeroes(),之后交由 Angular 处理,它会在构造出 HeroesComponent 的实例之后的某个合适的时机调用 ngOnInit。

 

显示全文