qrcode

马上订阅,开启修仙之旅

Angular 自定义管道

本文将使用 UltimateAngular/angular-pro-src 中的示例,来一步步介绍自定义管道的相关知识。在该示例中,我们将定义一个 FileSizePipe 管道,它用于实现对文件大小进行格式化显示。

切回正题,我们先来看一下数据:

1
2
3
4
5
[
{ name: 'logo.svg', size: 2120109, type: 'image/svg' },
{ name: 'banner.jpg', size: 18029, type: 'image/jpg' },
{ name: 'background.png', size: 1784562, type: 'image/png' }
];

上面数组中每一项表示一个文件信息,含有以下字段:

  • name —— 文件名称
  • size —— 文件大小(字节)
  • type —— 文件类型

接下来我们需要实现的功能,是在显示文件信息时,把字节(Byte)转换为兆(MB)。要实现此功能,我们可以利用 Angular 的管道。在 Angular 中自定义管道,需要按照以下步骤:

  • 使用 @Pipe 装饰器定义 Pipe 的 Metadata 信息,如 Pipe 的名称 —— name 属性。
  • 实现 PipeTransform 接口中定义的 transform 方法。

现在我们来新建一个 filesize.pipe.ts 文件,然后定义一个 FileSizePipe 类,该实现实现了 PipeTransform 接口,具体如下:

1
2
3
4
5
6
7
8
9
10
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'filesize'
})
export class FilesizePipe implements PipeTransform {
transform(value: any, args?: any): any {
return null;
}
}

字节与兆的转换规则:

1
1 MB = 1024 KB = 1024 * 1024 B

因此按照以上的转换规则,我们可以很容易把字节(Byte)转换为 兆(MB),需要注意的是要处理小数位,这里我们只保留两位小数:

1
2
3
4
5
6
7
8
9
10
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'filesize'
})
export class FileSizePipe implements PipeTransform {
transform(size: number, extension: string = 'MB') {
return (size / (1024 * 1024)).toFixed(2) + extension;
}
}

定义完 FileSizePipe 管道,我们就可以直接在模板上使用它了:

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
import { Component, OnInit } from '@angular/core';

interface File {
name: string,
size: any,
type: string
}

@Component({
selector: 'my-app',
template: `
<div>
<div *ngFor="let file of files">
<p>{{ file.name }}</p>
<p>{{ file.size | filesize }}</p>
</div>
</div>
`
})
export class AppComponent implements OnInit {
files: File[];
ngOnInit() {
this.files = [
{ name: 'logo.svg', size: 2120109, type: 'image/svg' },
{ name: 'banner.jpg', size: 18029, type: 'image/jpg' },
{ name: 'background.png', size: 1784562, type: 'image/png' }
];
}
}

需要注意的是与 AngularJS 1.x 的 Filter 一样,Angular 管道也支持参数和管道链。其实,要实现上述的功能,除了在页面模板中使用管道之外,我们也可以在页面渲染前,对数据源进行处理。

前面我们已经在 FileSizePipe 类中定义了 transform 方法,用于实现文件大小进行格式处理。那么现在问题来了,我们可以直接利用 FileSizePipe 对象提供的 transform 方法,来对数据源进行处理么?答案是可以的。

下面我们来介绍在组件类中,如何使用管道服务:

  1. 配置 Provider:
1
2
3
4
5
6
7
8
9
import { FilesizePipe } from './filesize.pipe';

@Component({
selector: 'my-app',
template: `...`,
providers: [
FilesizePipe
]
})
  1. 注入 FileSizePipe 管道服务:
1
2
3
constructor(
private fileSizePipe: FileSizePipe
) {}
  1. 数据处理
1
2
3
4
5
6
7
8
9
10
11
mapped: File[];

ngOnInit() {
this.mapped = this.files.map(file => {
return {
name: file.name,
type: file.type,
size: this.fileSizePipe.transform(file.size, 'MB')
};
});
}
  1. 数据展示
1
2
3
4
5
6
<div>
<div *ngFor="let file of mapped">
<p>{{ file.name }}</p>
<p>{{ file.size }}</p>
</div>
</div>

最终完整的示例如下:

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
52
53
54
import { Component, OnInit } from '@angular/core';
import { FileSizePipe } from './filesize.pipe';

interface File {
name: string,
size: any,
type: string
}

@Component({
selector: 'my-app',
template: `
<h3>模板使用管道</h3>
<div>
<div *ngFor="let file of files">
<p>{{ file.name }}</p>
<p>{{ file.size | filesize }}</p>
</div>
</div>
<h3>组件类中使用管道</h3>
<div>
<div *ngFor="let file of mapped">
<p>{{ file.name }}</p>
<p>{{ file.size }}</p>
</div>
</div>
`,
providers: [
FileSizePipe
]
})
export class AppComponent implements OnInit {
files: File[];
mapped: File[];

constructor(
private fileSizePipe: FileSizePipe
) {}
ngOnInit() {
this.files = [
{ name: 'logo.svg', size: 2120109, type: 'image/svg' },
{ name: 'banner.jpg', size: 18029, type: 'image/jpg' },
{ name: 'background.png', size: 1784562, type: 'image/png' }
];

this.mapped = this.files.map(file => {
return {
name: file.name,
type: file.type,
size: this.fileSizePipe.transform(file.size, 'MB')
};
});
}
}

有兴趣的同学,也可以直接浏览线上的示例 —— angular-filesize-pipe


欢迎小伙伴们订阅前端修仙之路,及时阅读 Angular、RxJS、TypeScript 和 Node.js 最新文章。

qrcode