Angular 中的管道

Angular 中的管道

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'
})

// 只需实现 PipeTransform 接口即可
// 内部仅有一个 transform 方法
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 可以直接在模版当中使用 PromiseObservable 对象,而不需要通过定义一个类的成员属性来存储返回的结果,下面来看两个例子,PromiseObservable

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
// Promise
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)
})
}
}


// Observables
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,随着时间的推移发出多个值,可以取消的,支持 mapfilterreduce 等操作符,延迟执行,当订阅的时候才会开始执行

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
// 使用 rxjs 中的共享操作符
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() {
// 调用 connect() 方法的时候,将主动执行订阅操作
this.person$.connect()
}

// 调用 publishReplay() 方法后将返回一个 ConnectableObservable 对象
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 执行流程

如下图

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×