更新時間 - 2017-03-20 16:15;
更新內容 - 日期格式化示例輸出結果,感謝 天之驕子 刊誤json
Angular 2 中 Pipe(管道) 與 Angular 1.x 中的 filter(過濾器) 的做用的是同樣的。它們都是用來對輸入的數據進行處理,如大小寫轉換、數值和日期格式化等。app
String -> String函數
UpperCasePipeui
LowerCasePipethis
TitleCasePipespa
Number -> Stringprototype
DecimalPipe代理
PercentPipecode
CurrencyPipeorm
Object -> String
JsonPipe
DatePipe
Tools
SlicePipe
AsyncPipe
I18nPluralPipe
I18nSelectPipe
1.大寫轉換
<div> <p ngNonBindable>{{ 'Angular' | uppercase }}</p> <p>{{ 'Angular' | uppercase }}</p> <!-- Output: ANGULAR --> </div>
2.小寫轉換
<div> <p ngNonBindable>{{ 'Angular' | lowercase }}</p> <p>{{ 'Angular' | lowercase }}</p> <!-- Output: angular --> </div>
3.數值格式化
<div> <p ngNonBindable>{{ 3.14159265 | number: '1.4-4' }}</p> <p>{{ 3.14159265 | number: '1.4-4' }}</p> <!-- Output: 3.1416 --> </div>
4.日期格式化
<div> <p ngNonBindable>{{ today | date: 'shortTime' }}</p> <p>{{ today | date: 'shortTime' }}</p> <!-- Output: 以當前時間爲準,輸出格式:10:40 AM --> </div>
5.JavaScript 對象序列化
<div> <p ngNonBindable>{{ { name: 'semlinker' } | json }}</p> <p>{{ { name: 'semlinker' } | json }}</p> <!-- Output: { "name": "semlinker" } --> </div>
管道能夠接收任意數量的參數,使用方式是在管道名稱後面添加 : 和參數值。如 number: '1.4-4' ,若須要傳遞多個參數則參數之間用冒號隔開,具體示例以下:
<div> <p ngNonBindable>{{ 'semlinker' | slice:0:3 }}</p> <p>{{ 'semlinker' | slice:0:3 }}</p> <!-- Output: sem --> </div>
咱們能夠將多個管道鏈接在一塊兒,組成管道鏈對數據進行處理。
<div> <p ngNonBindable>{{ 'semlinker' | slice:0:3 | uppercase }}</p> <p>{{ 'semlinker' | slice:0:3 | uppercase }}</p> <!-- Output: SEM --> </div>
完整示例
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <div> <p ngNonBindable>{{ 'Angular' | uppercase }}</p> <p>{{ 'Angular' | uppercase }}</p> </div> <div> <p ngNonBindable>{{ 'Angular' | lowercase }}</p> <p>{{ 'Angular' | lowercase }}</p> </div> <div> <p ngNonBindable>{{ 3.14159265 | number: '1.4-4' }}</p> <p>{{ 3.14159265 | number: '1.4-4' }}</p> </div> <div> <p ngNonBindable>{{ today | date: 'shortTime' }}</p> <p>{{ today | date: 'shortTime' }}</p> </div> <div> <p ngNonBindable>{{ { name: 'semlinker' } | json }}</p> <p>{{ { name: 'semlinker' } | json }}</p> </div> <div> <p ngNonBindable>{{ 'semlinker' | slice:0:3 }}</p> <p>{{ 'semlinker' | slice:0:3 }}</p> </div> <div> <p ngNonBindable>{{ 'semlinker' | slice:0:3 | uppercase }}</p> <p>{{ 'semlinker' | slice:0:3 | uppercase }}</p> </div> `, }) export class AppComponent { today = new Date(); }
自定義管道的步驟:
使用 @Pipe 裝飾器定義 Pipe 的 metadata 信息,如 Pipe 的名稱 - 即 name 屬性
實現 PipeTransform 接口中定義的 transform 方法
1.1 WelcomePipe 定義
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'welcome' }) export class WelcomePipe implements PipeTransform { transform(value: string): string { if(!value) return value; if(typeof value !== 'string') { throw new Error('Invalid pipe argument for WelcomePipe'); } return "Welcome to " + value; } }
1.2 WelcomePipe 使用
<div> <p ngNonBindable>{{ 'semlinker' | welcome }}</p> <p>{{ 'semlinker' | welcome }}</p> <!-- Output: Welcome to semlinker --> </div>
當 WelcomePipe 的輸入參數,即 value 值爲非字符串時,如使用 123,則控制檯將會拋出如下異常:
EXCEPTION: Error in ./AppComponent class AppComponent - inline template:23:9 caused by: Invalid pipe argument for WelcomePipe
2.1 RepeatPipe 定義
import {Pipe, PipeTransform} from '@angular/core'; @Pipe({name: 'repeat'}) export class RepeatPipe implements PipeTransform { transform(value: any, times: number) { return value.repeat(times); } }
2.2 RepeatPipe 使用
<div> <p ngNonBindable>{{ 'lo' | repeat:3 }}</p> <p>{{ 'lo' | repeat:3 }}</p> <!-- Output: lololo --> </div>
pure 管道:僅當管道輸入值變化的時候,才執行轉換操做,默認的類型是 pure 類型。(備註:輸入值變化是指原始數據類型如:string、number、boolean 等的數值或對象的引用值發生變化)
impure 管道:在每次變化檢測期間都會執行,如鼠標點擊或移動都會執行 impure 管道
1.Pipe 相關接口與 PipeDecorator
Pipe 接口定義
export interface Pipe { name: string; pure?: boolean; }
PipeDecorator
export const Pipe: PipeDecorator = <PipeDecorator>makeDecorator('Pipe', { name: undefined, pure: true, // 默認是pure });
PipeTransform 接口定義
export interface PipeTransform { transform(value: any, ...args: any[]): any; }
2.RepeatPipe 詳解
2.1 RepeatPipe 定義
@Pipe({name: 'repeat'}) export class RepeatPipe implements PipeTransform { transform(value: any, times: number) { return value.repeat(times); } }
2.2 RepeatPipe 轉換爲 ES 5 代碼片斷
__decorate = (this && this.__decorate) || function (decorators, target, key, desc) {...}; var core_1 = require('@angular/core'); var RepeatPipe = (function () { function RepeatPipe() { } RepeatPipe.prototype.transform = function (value, times) { if (!value) return; return value.repeat(times); }; RepeatPipe = __decorate([ core_1.Pipe({ name: 'repeat' }), // 調用PipeDecorator返回TypeDecorator函數 __metadata('design:paramtypes', []) ], RepeatPipe); return RepeatPipe; }());
2.3 經過 Reflect API 保存後的對象信息
2.4 管道解析 - PipeResolver 源碼片斷
// @angular/compiler/src/pipe_resolver.ts @CompilerInjectable() export class PipeResolver { constructor(private _reflector: ɵReflectorReader = ɵreflector) {} // 經過內部的ɵReflectorReader對象提供的API讀取metadata信息 resolve(type: Type<any>, throwIfNotFound = true): Pipe { const metas = this._reflector.annotations(resolveForwardRef(type)); if (metas) { // 讀取保存的Pipe metadata 信息 const annotation = ListWrapper.findLast(metas, _isPipeMetadata); if (annotation) { return annotation; } } if (throwIfNotFound) { throw new Error(`No Pipe decorator found on ${stringify(type)}`); } return null; } }
2.5 RepeatPipe 管道的建立與執行
2.5.1 管道的建立
// JS has NaN !== NaN function looseIdentical(a, b): boolean { return a === b || typeof a === 'number' && typeof b === 'number' && isNaN(a) && isNaN(b); } // 用於檢測管道的輸入值或參數值是否變化,若發生變化則自動調用管道transform轉換函數 function jit_pureProxy214(fn) { var result; var v0 = UNINITIALIZED; // { toString: function() { return 'CD_INIT_VALUE'} }; var v1 = UNINITIALIZED; return function (p0, p1) { if (!looseIdentical(v0, p0) || !looseIdentical(v1, p1)) { v0 = p0; // p0: "lo" v1 = p1; // p1: 3 // fn: transform(value: any, times: number) { return value.repeat(times); } result = fn(p0, p1); // 調用管道的transform轉換函數 } return result; }; } self._pipe_repeat_6 = new jit_RepeatPipe18(); // 建立RepeatPipe對象 self._pipe_repeat_6_0 = jit_pureProxy214( // 代理RepeatPipe中transform函數 self._pipe_repeat_6.transform.bind(self._pipe_repeat_6));
2.5.2 管道的執行
在 Angular 執行變化檢測時,會自動調用管道中的 transform 方法
var currVal_100 = jit_inlineInterpolate21(1,'',valUnwrapper.unwrap( jit_castByValue22 (self._pipe_repeat_6_0, self._pipe_repeat_6.transform)('lo',3)),'');
本文介紹了 Angular 2 中的經常使用內建管道的用法和管道的分類,同時也介紹了 pure 和 impure 管道的區別。 此外咱們經過兩個示例展現瞭如何自定義管道,最後詳細分析了 RepeatPipe 管道的工做原理。建議讀者更改 RepeatePipe 的 pure 屬性爲 false,體驗一下 impure 管道。