Angular
中的管道主要是用来对字符串、货币金额、日期和其他显示数据进行转换和格式化,管道通常是一些简单的函数,可以在模板表达式中用来接受输入值并返回一个转换后的值,我们先来看看一些简单的使用场景
1 2 3 4 5 6 7 8 9
| <p>生日是 {{ birthday | data: 'yyyy-MM-dd' }}</p>
<p>圆周率为 {{ 3.14159265 | number: '1.2-2' }}</p>
<p>转为大写 {{ 'Angular' | uppercase }}</p>
<p>转为小写 {{ 'Angular' | lowercase }}</p>
<p>格式化 {{ { name: 'semlinker' } | json }}</p>
|
管道参数
管道可以接收任意数量的参数,使用方式是在管道名称后面添加 :
和参数值,如 number: '1.2-2'
,若需要传递多个参数则参数之间用冒号隔开
1
| <p>{{ 'semlinker' | slice:0:3 }}</p>
|
管道链
可以将多个管道连接在一起,组成管道链对数据进行处理
1
| <p>{{ 'semlinker' | slice:0:3 | uppercase }}</p>
|
自定义管道
管道是一个带有管道元数据装饰器的类,与组件和模块类似,就是一个简单的 TypeScript
类,通过 @pipe
装饰器来告诉 Angular
这是一个管道类,然后去实现 PipeTransform
接口即可,一个简单的管道,如果跟随参数,则返回和参数相乘的值,如果没有传递参数,则返回原值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { Pipe, PipeTransform } from '@angular/core'
@Pipe({ name: 'formatNumber' })
export class TestPipe implements PipeTransform { transform(value: number, args?: number): any { if (!args) { args = 1 } return value * args } }
|
然后使用也很简单
1
| <div>{{num | formatNumber: '2'}}</div>
|
在构造函数当中使用管道
一个小技巧,但不是经常使用
1 2 3 4 5 6 7 8 9 10
| import { DatePipe } from '@angular/common'
class MyService {
constructor(private datePipe: DatePipe) {}
transformDate(date) { this.datePipe.transform(myDate, 'yyyy-MM-dd') } }
|
AsyncPipe(异步管道)
使用 AsyncPipe
可以直接在模版当中使用 Promise
和 Observable
对象,而不需要通过定义一个类的成员属性来存储返回的结果,下面来看两个例子,Promise
和 Observable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import { Component } from '@angular/core'
@Component({ selector: 'exe-promise-pipe', template: ` <h4>Promise with AsyncPipeComponent</h4> <p>{{ promise | async }}</p> ` }) export class PromiseAsyncPipeComponent { promise: Promise<string> constructor() { this.promise = this.getPromise() }
getPromise(): Promise<string> { return new Promise((resolve, reject) => { setTimeout(() => { resolve(`Promise with AsyncPipe complete!`) }, 2000) }) } }
import { Component } from '@angular/core' import { Observable } from 'rxjs/Rx'
@Component({ selector: 'exe-observable-pipe', template: ` <h4>Observable with AsyncPipe Component</h4> <p>{{ observable | async }}</p> ` }) export class ObservableAsyncPipeComponent { observable: Observable<number>
constructor() { this.observable = this.getObservable() }
getObservable(): Observable<number> { return Observable .interval(1000) .take(10) .map(v => v * v) } }
|
两者的区别
Promise
,返回单个值,不可取消的
Observable
,随着时间的推移发出多个值,可以取消的,支持 map
、filter
、reduce
等操作符,延迟执行,当订阅的时候才会开始执行
AsyncPipe 会发送多次请求
比如如下情况
1 2 3 4 5 6 7 8 9 10
| @Component({ selector: 'exe-app', template: ` <div> <p>{{ (person$ | async)?.id }}</p> <p>{{ (person$ | async)?.title }}</p> <p>{{ (person$ | async)?.body }}</p> </div> ` })
|
几种解决办法
使用 share()
1 2 3
| this.http.get(url) .map(res => res.json()).share()
|
使用 publishReplay()
但是页面当中如果有按钮存在的情况,再次请求同样的地址还是会发送请求,这时可以使用 publishReplay()
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| constructor(private http: Http) { this.preparePersonInfo() }
ngOnInit() { this.person$.connect() }
preparePersonInfo() { this.person$ = this.http.get(url) .map(res => res.json()).publishReplay() }
|
如果只需要从服务器获取数据并显示数据
可以使用 Promise
来修复 AsyncPipe
发送多次请求的问题
1 2
| this.person = this.http.get(url) .map(res => res.json()).toPromise()
|
AsyncPipe 执行流程
如下图