我们还可以写自己的自定义管道。 下面就是一个名叫ExponentialStrengthPipe
的管道,它可以放大英雄的能力:
app/exponential-strength.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
/*
* Raise the value exponentially
* Takes an exponent argument that defaults to 1.
* Usage:
* value | exponentialStrength:exponent
* Example:
* {{ 2 | exponentialStrength:10}}
* formats to: 1024
*/
@Pipe({name: 'exponentialStrength'})
export class ExponentialStrengthPipe implements PipeTransform {
transform(value: number, exponent: string): number {
let exp = parseFloat(exponent);
return Math.pow(value, isNaN(exp) ? 1 : exp);
}
}
在这个管道的定义中体现了几个关键点:
-
管道是一个带有“管道元数据(pipe metadata)”装饰器的类。
-
这个管道类实现了
PipeTransform
接口的transform
方法,该方法接受一个输入值和一些可选参数,并返回转换后的值。 -
当每个输入值被传给
transform
方法时,还会带上另一个参数,比如我们这个管道中的exponent
(放大指数)。 -
我们通过
@Pipe
装饰器告诉Angular:这是一个管道。该装饰器是从Angular的core
库中引入的。 -
这个
@Pipe
装饰器允许我们定义管道的名字,这个名字会被用在模板表达式中。它必须是一个有效的JavaScript标识符。 比如,我们这个管道的名字是exponentialStrength
。
PipeTransform接口
transform
方法是管道的基本要素。 PipeTransform
接口中定义了它,并用它指导各种工具和编译器。 严格来说,它是可选的。Angular不会管它,而是直接查找并执行transform
方法。
现在,我们需要一个组件来演示这个管道。
app/power-booster.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'power-booster',
template: `
<h2>Power Booster</h2>
<p>Super power boost: {{2 | exponentialStrength: 10}}</p>
`
})
export class PowerBoosterComponent { }
要注意的有两点:
-
我们使用自定义管道的方式和内置管道完全相同。
-
我们必须在
AppModule
的declarations
数组中包含这个管道。
如果我们忘了列出这个自定义管道,Angular就会报告一个错误。 在前一个例子中我们没有把DatePipe
列进去,这是因为Angular所有的内置管道都已经预注册过了。 但自定义管道必须手工注册。
如果我们试一下这个在线例子,就可以通过修改值和模板中的可选部分来体会其行为。
能力倍增计算器(加分项)
仅仅升级模板来测试这个自定义管道其实没多大意思。 我们干脆把这个例子升级为“能力倍增计算器”,它可以把该管道和使用ngModel
的双向数据绑定组合起来。
/app/power-boost-calculator.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'power-boost-calculator',
template: `
<h2>Power Boost Calculator</h2>
<div>Normal power: <input [(ngModel)]="power"></div>
<div>Boost factor: <input [(ngModel)]="factor"></div>
<p>
Super Hero Power: {{power | exponentialStrength: factor}}
</p>
`
})
export class PowerBoostCalculatorComponent {
power = 5;
factor = 1;
}