(六)Angular4 英雄征途HeroConquest-服务service

xiaoxiao2021-02-28  131

(六)Angular4 英雄征途HeroConquest-服务

为了不再把相同的代码复制一遍又一遍,我们要创建一个单一的可复用的数据服务,并且把它注入到需要它的那些组件中。 使用单独的服务可以保持组件精简,使其集中精力为视图提供支持,并且,借助模拟(Mock)服务,可以更容易的对组件进行单元测试,在本节中将实现一个异步的数据请求机制Promise。承接上一节,在这一节中, 从组件中移除数据访问逻辑意味着你可以随时更改这些实现方式,而不影响需要这些英雄数据的组件。


创建服务hero-get.service.ts

文件命名约定规则:服务名称的小写形式(基本名),加上.service后缀。 如果服务名称包含多个单词,我们就把基本名部分写成中线形式 (dash-case)。 例如,本节要创建的HeroGetService服务应该被定义在hero-get.service.ts文件中。

// 导入了 Angular 的Injectable函数 import { Injectable } from '@angular/core'; // 导入属性HeroProperty import { HeroProperty } from './heroproperty'; // 导入数据HeroArray import { HeroArray } from './mock-hero-data'; //作为@Injectable()装饰器使用这个函数,当 TypeScript //看到@Injectable()装饰器时,就会记下本服务的元数据。 //如果 Angular 需要往这个服务中注入其它依赖,就会使用//这些元数据。虽然此时HeroService还没有任何依赖,但 //我们还是得加上这个装饰器。 作为一项最佳实践,无论是 //出于提高统一性还是减少变更的目的, 都应该从一开始就 //加上@Injectable()装饰器。 @Injectable() export class HeroGetService { //定义一个获取HeroArray数据的方法,这个HeroArray数据 //可以来自Web服务、本地存储或模拟数据源,本节就是模拟 //数据源来自mock-hero-data模块。 我们请求一个异步服务 //去做点什么,并且给它一个回调函数。 它此时它去获取数据 //,一旦完成,它就会调用我们的回调函数,并通过参 //数把工作结果或者错误信息传给我们。通过返回一个立即解 //决的承诺的方式,模拟了一个超快、零延迟的超级服务器。 getHeros(): Promise<HeroProperty[]> { return Promise.resolve(HeroArray); } }

app.component.ts文件

import { Component, OnInit } from '@angular/core'; import { HeroDetailComponent} from './hero-detail.component'; import { HeroArray } from './mock-hero-data'; import { HeroProperty} from './heroproperty'; //在app.component.ts这个组件中导入HeroGetService //以便使用该服务 import { HeroGetService} from './hero-get.service'; @Component({ AppComponent的模板中。 // 这就是所谓的自定义标签 selector: 'app-root', template: `<h1>{{title}}</h1> <!--上一节代码begin--> <br> <h2>              -------{{from}}</h2> <ul> <li> <div><label>ID:</label>{{hero.id}} <label> name:</label>{{hero.name}}</div> </li> </ul> <div> <label>name: </label> <input [(ngModel)]="hero.name" > <label>ID: </label> <input [ngModel]="hero.id" (ngModelChange)="hero.id=$event"> </div> <div> <ul class="heroes"> <li *ngFor="let onehero of Heroes" (click)="onSelect(onehero)" [class.selected]="onehero===selectedHero"> <span class="badge">ID:{{onehero.id}}</span> {{onehero.name}} </li> </ul> </div > <app-hero-detail [DetailHero]="selectedHero"></app-hero-detail> <!--上一节代码end--> ` , styleUrls: ['./app.component.css'], //注册一个HeroGetService提供商,来告诉注入器如何创 //建HeroGetService。 因此在@Component组件的元数据 //底部添加providers数组属性 providers: [HeroGetService] }) export class AppComponent implements OnInit { //如下:添加一个构造函数,并定义一个私有属性。 //我们修改了HeroService的构造函数,我们不得不找出创 //建过此服务的每一处代码,并修改它。 围着补丁代码转圈 //很容易导致错误,还会增加测试负担。我们每次使用new都 //会创建一个新的服务实例(herogetService = new HeroGetService();)。 如果这个服务需要缓存英雄列 //表,并把这个缓存共享给别人呢?怎么办? 没办法,做不 //到。我们把AppComponent锁定到HeroGetService的一个 //特定实现。 我们很难在不同的场景中切换实现。 例如,能离 //线操作吗?能在测试时使用不同的模拟版本吗?这可不容易。 //构造函数自己什么也不用做,它在参数中定义了一个私有 //的herogetService属性,并把它标记为注入HeroGetService的实例。 constructor(private herogetSevice: HeroGetService) {} title = 'My conquest is the sea of stars.'; from = 'Reinhard von Lohengramm'; hero: HeroProperty = { id: 9527, name: 'Lee', }; // Heros = HeroArray; // 将以上改为如下,添加一个尚未初始化的Heros属性 Heroes: HeroProperty[]; selectedHero: HeroProperty; onSelect(each: HeroProperty): void { this.selectedHero = each; } getHerosData(): void { this.herogetSevice.getHeros().then(heroesdata => this.Heroes = heroesdata); //this.heroes = this.heroService.getHeroes();并不能做到异步获取数据 //HeroService立即返回一个模拟的英雄列表,它的 //远端服务器获取。当使用远端服务器时,用户不会等待服务 //器的响应。换句话说,用户没法在等待期间阻塞浏览器界 //面。为了协调视图与响应,我们可以使用(Promise),它是一 //种异步技术,它会改变getHeroes()方法的签名。它就是 //一个承诺,在有了结果时,它承诺会回调我们。 英雌调用 //一个异步服务去执行数据请求,并且给它一个回调函数。 //请求一旦完成,它就会调用我们的回调函数,并通过参数把工 //作结果或者错误信息传给我们。把回调函数作为参数传给承 //诺实例对象的then方法。在回调函数中,我们把服务返回的英 //雄数组赋值给组件的Heroes属性。 } ngOnInit(): void { this.getHerosData(); } }

heroproperty.ts文件

export class HeroProperty { id: number; name: string; }

mock-hero-data.ts文件

import { HeroProperty} from './heroproperty'; export const HeroArray: HeroProperty[] = [ { id: 1, name: 'Asimov' }, { id: 2, name: 'IronMan' }, { id: 3, name: 'Gen' }, { id: 4, name: 'AnglovLee' } ];

hero-detail.component.ts文件

import { Component, Input } from '@angular/core'; import { HeroProperty} from './heroproperty'; @Component({ selector: 'app-hero-detail', template: ` <!--herodetail--> <div *ngIf="DetailHero"> <h2>{{DetailHero.name}} details!</h2> <label>id: </label>{{DetailHero.id}} <div> <label>name: </label> <input [(ngModel)]="DetailHero.name" placeholder="name"/> </div> </div> <!--herodetail--> `, }) export class HeroDetailComponent { @Input() DetailHero: HeroProperty; }

app.module.ts文件

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { HeroDetailComponent} from './hero-detail.component'; @NgModule({ declarations: [ AppComponent, HeroDetailComponent ], imports: [ BrowserModule, FormsModule, ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
转载请注明原文地址: https://www.6miu.com/read-36276.html

最新回复(0)