购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.6 使用服务

本节将创建用户服务UserService。UserService用于为视图提供数据。并且,不需要使用new关键字来创建此服务的实例,而要依靠Angular的依赖注入机制把服务实例注入UsersComponent组件的构造函数中。

4.6.1 服务的好处

使用服务有以下好处:

(1)有利于代码分层管理。在一个模块中,服务位于处理核心业务逻辑层。

(2)依靠Angular的依赖注入机制,能够轻松地将服务注入需要使用服务的组件中,从而简化了服务的实例化。

4.6.2 创建UserService服务

使用Angular CLI创建一个名为“user”的服务。

可以在控制台上看到如下输出信息:

该命令在src/app/user.service.ts中生成的是UserService类的骨架。UserService类的代码如下:

在src/app/user.service.spec.ts中生成的是UserService类的测试代码,如下:

注意:这个新的服务导入了Angular的Injectable符号,并且给这个服务类添加了@Injectable()装饰器。UserService类将会提供一个可注入的服务,并且它还可以拥有自己的待注入的依赖。目前它还没有依赖,但是很快就会有了。

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

如果你熟悉Java中的注解,那么这个@Injectable()装饰器可以被简单地理解为Java中的@Inject注解。

UserService类用于提供用户数据的查询,而且这个服务的调用方是不需要关心UserService类的数据来源的。UserService类可以从任何地方获取数据,如Web 服务、本地存储(LocalStorage)或一个模拟的数据源。

我们将要从组件中移除数据访问逻辑,并将数据访问逻辑移到UserService类中,这样组件只需要依赖UserService类来提供数据。这意味着,将来任何时候都可以改变目前的UserService类的实现方式,而不用改动任何组件,因为这些组件不需要了解该服务的内部实现。

我们将原来在组件中实现的“获取模拟的用户列表”功能迁移至UserService类中。具体修改如下。

1. 导入 User USERS

在UserService类中导入User和USERS。

2. 添加一个 getUsers() 方法

在UserService类中添加一个getUsers()方法,让它返回模拟的用户列表。

4.6.3 提供UserService服务

在Angular把UserService服务注入UsersComponent组件之前,必须先把这个服务提供给依赖注入系统。可以通过注册提供商来做到这一点。提供商用来创建和交付服务,在这个例子中,它会对UserService类进行实例化,以提供该服务。

现在,需要确保UserService类已经作为该服务的提供商进行了注册。需要用一个注入器注册它。注入器就是一个对象,负责在需要时选取和注入该提供商。

在默认情况下,Angular CLI 的“ng generate service”命令会通过给@Injectable装饰器添加元数据的形式,为该服务把提供商注册到根注入器上。

如果你看看UserService前面的@Injectable()语句定义,就会发现providedIn元数据的值是'root'。

当你在顶层提供该服务时,Angular就会为UserService类创建一个单一的、共享的实例,并把它注入任何想要它的类上。在@Injectable元数据中注册该提供商,还能让Angular通过移除那些完全没有用过的服务来进行优化。

如果需要,也可以在不同的层次上注册提供商,比如,在UsersComponent组件中,在AppComponent中,或在AppModule中。比如,可以通过附加“-module=app”参数来告诉Angular CLI 要自动在模块级提供该服务。

现在,UserService类已经准备好注入UsersComponent组件中了。

4.6.4 修改UsersComponent组件

打开UsersComponent组件的类文件users.component.ts,删除USERS的导入语句,因为以后不会再用它了,转而导入UserService类。

把users属性的定义改为一句简单的声明。

1. 注入 UserService

向构造函数中添加一个私有的类型为UserService的服务实例userService,代码如下。

这个参数同时做了两件事。

● 声明了一个私有userService属性。

● 把userService属性标记为一个UserService类的注入点。

当Angular创建UsersComponen类时,依赖注入系统就会把这个userService参数设置为UserService类的单例对象。

2. 添加 getUsers() 函数

创建一个getUsers()函数,以便从服务中获取这些用户数据。

3. ngOnInit() 中调用 getUsers() 函数

你固然可以在构造函数中调用getUsers()函数,但那不是最佳实践。

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

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

4. 查看运行效果

执行“ng serve”命令以启动应用,在浏览器中访问http://localhost:4200/。该应用的运行效果应该跟之前是一样的。

4.6.5 使用Observable数据

Observable方式属于响应式编程(Reactive Programming),数据流是异步传输的。采用 Observable方式需要引入 RxJS 库(http://reactivex.io/rxjs/)。当然,Angular自带了RxJS库,我们开箱即用即可。

1. UserService 类中实现 Observable

打开UserService类的文件user.service.ts,并从RxJS库中导入Observable和of符号。

把 getUsers()方法改成下面这样:

其中,of(USERS)会返回一个Observable<User[]>,它会发出单个值,这个值就是这些模拟用户所在的数组。

2. UsersComponent 中订阅

UserService.getUsers()方法之前返回一个User[],现在它返回的是Observable<User[]>。所以,必须在UsersComponent中修改使用UserService.getUsers()方法的方式。

找到getUsers()方法,并且把它替换为如下代码:

Observable.subscribe()是关键的差异点。这样,只要数据源发生变化,this.users的值就能立即得到最新的变化,实现异步。

当然,目前还无法体会到Observable所带来的好处,因为现在的数据是模拟的、硬编在代码里的。在后续章节中,还会继续展示Observable所带来的响应式编程的好处。

4.6.6 显示消息

在本节中,我们将:

● 添加一个MessagesComponent,它在屏幕的底部显示应用中的消息。

● 创建一个可注入的、全应用级别的MessageService,用于发送要显示的消息。

● 把MessageService注入UserService类中。

● 当UserService类成功获取了用户数据时显示一条消息。

1. 创建 MessagesComponent

使用Angular CLI创建MessagesComponent。

Angular CLI在src/app/messages中创建了组件文件,并且把MessagesComponent声明在AppModule 中。详细的控制台输出信息如下:

修改AppComponent的模板文件app.component.html来显示所生成的MessagesComponent。

这样,就可以在页面的底部看到来自MessagesComponent的默认内容。

2. 创建 MessageService

使用Angular CLI在src/app中创建MessageService。

MessageService创建完成之后,能够在控制台上看到详细的输出信息,如下:

打开MessageService的文件message.service.ts,并把它的内容修改成如下这样:

该服务对外暴露了它的 messages 缓存及两个方法。

● add()方法用于向缓存中添加一条消息。

● clear()方法用于清空缓存。

3. MessageService 注入 UserService

我们将实现一个典型的“服务中的服务”场景:把MessageService注入UserService中,而 UserService又被注入UsersComponent 中。

重新打开 UserService 的文件user.service.ts,并且导入 MessageService。

修改构造函数constructor(),添加一个私有的messageService属性。Angular将会在创建 UserService时把MessageService的单例注入这个属性中。

4. UserService 中发送一条消息

修改getUsers()方法,在获取到用户列表时发送一条消息。

5. UserService 中显示消息

MessagesComponent可以显示所有消息,包括当UserService获取到用户列表时发送的那条消息。

打开MessagesComponent的文件messages.component.ts,并且导入MessageService。

修改MessagesComponent的构造函数,添加一个公有的messageService属性。Angular将会在创建MessagesComponent的实例时把MessageService的实例注入这个属性中。

这个messageService 属性必须是公有属性,因为你将会在模板中绑定到它。

提示:

Angular只会绑定到组件的公有属性。

6. 绑定到 MessageService

把Angular CLI生成的MessagesComponent的模板文件messages.component.html修改成如下这样:

这个模板直接绑定到了组件的messageService属性上。其中,

●*ngIf只有在有消息时才会显示消息区。

●*ngFor用来在一系列<div>标签中展示消息列表。

● Angular的事件绑定机制把按钮的click事件绑定到了MessageService.clear()上。

为了让消息变得好看,需要把样式代码添加到messages.component.css中,这些样式只会作用于MessagesComponent。

7. 运行查看效果

执行“ng serve”命令以启动应用。访问“http://localhost:4200”并滚动到底部,就会在消息区看到来自UserService的消息。单击“clear”按钮,消息区不见了。

效果如图4-13所示。

图4-13 运行效果 wCXcHcREaXR9kiLPI3F7tGqdaOAvHa2eJTYkLxYBNDFJFxkLHIsxvQf30vtCcU3q

点击中间区域
呼出菜单
上一章
目录
下一章
×