本文将使用 UltimateAngular/angular-pro-src 中的示例,来一步步介绍自定义管道的相关知识。在该示例中,我们将定义一个 FileSizePipe
管道,它用于实现对文件大小进行格式化显示。
切回正题,我们先来看一下数据:
代码语言:javascript复制[
{ 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 接口,具体如下:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filesize'
})
export class FilesizePipe implements PipeTransform {
transform(value: any, args?: any): any {
return null;
}
}
字节与兆的转换规则:
代码语言:javascript复制1 MB = 1024 KB = 1024 * 1024 B
因此按照以上的转换规则,我们可以很容易把字节(Byte)转换为 兆(MB),需要注意的是要处理小数位,这里我们只保留两位小数:
代码语言:javascript复制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 管道,我们就可以直接在模板上使用它了:
代码语言:javascript复制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
方法,来对数据源进行处理么?答案是可以的。
下面我们来介绍在组件类中,如何使用管道服务:
- 配置 Provider:
import { FilesizePipe } from './filesize.pipe';
@Component({
selector: 'my-app',
template: `...`,
providers: [
FilesizePipe
]
})
- 注入 FileSizePipe 管道服务:
constructor(
private fileSizePipe: FileSizePipe
) {}
- 数据处理
mapped: File[];
ngOnInit() {
this.mapped = this.files.map(file => {
return {
name: file.name,
type: file.type,
size: this.fileSizePipe.transform(file.size, 'MB')
};
});
}
- 数据展示
<div>
<div *ngFor="let file of mapped">
<p>{{ file.name }}</p>
<p>{{ file.size }}</p>
</div>
</div>
最终完整的示例如下:
代码语言:javascript复制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。