Angular 自定义管道

2019-11-05 16:11:38 浏览数 (1)

本文将使用 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 接口,具体如下:

代码语言:javascript复制
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:
代码语言:javascript复制
import { FilesizePipe } from './filesize.pipe';

@Component({
  selector: 'my-app',
  template: `...`,
  providers: [
    FilesizePipe
  ]
})
  • 注入 FileSizePipe 管道服务:
代码语言:javascript复制
constructor(
  private fileSizePipe: FileSizePipe
 ) {}
  • 数据处理
代码语言:javascript复制
mapped: File[];

ngOnInit() {
  this.mapped = this.files.map(file => {
    return {
      name: file.name,
      type: file.type,
      size: this.fileSizePipe.transform(file.size, 'MB')
    };
  });
}
  • 数据展示
代码语言:javascript复制
<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。

0 人点赞