Stories

Detail Return Return

Angular 管道 - Stories Detail

問題

在寫活動管理詳情的時候不知道怎麼用內置的日期管道,自己寫了一個管道,同時在管道使用時遇到問題。

查看後發現ActivityScalePipe在新建時聲明在了Activity模塊中,而我想在view模塊中使用,就又將管道聲明在了view模塊中,這樣就導致了上面的問題。最開始想到的解決辦法時在view不用聲明管道,在Activity中export ActivityScalePipe,然後在view模塊中引入Activity模塊,結果導致產生循環,因為在Activity模塊中已經引入了view模塊。後來直接將管道聲明在view模塊中,然後再export管道,問題解決。
但後來想到這樣解決不太好,因為如果有其他模塊需要用到這個管道,那麼這個模塊就需要引入整個view模塊,顯然這種寫法並不合理,於是重新修改,將管道聲明在pipe模塊中,這樣無論那個模塊想使用管道都只需要引入pipe管道。後來查看其他管道也是使用這種寫法。

通過這個過程對組件與模塊之間關係和模塊之間的關係有了更深的理解。
組件依賴於模塊,存在於模塊,組件若想成動運行,則必然是運行於某個模塊之中。組件成功運行的前提,是在模塊中被成功地實例化,模塊能夠成功實例化某個組件的前提是模塊擁有組件想要的一切。
注意:管道只能被聲明在一個模塊中

管道

官方文檔

簡介

管道簡單來説可以理解為一個對數據轉化的東西,數據在管道一端流入,經過管道轉化後以另一種形式在另一端流出。
管道使用 數據 | 管道名稱
如: 日期管道名稱為‘data’

<p>The hero's birthday is {{ birthday | date }}</p>

管道串聯

The chained hero's birthday is
{{ birthday | date | uppercase}}

自定義管道

要把類標記為管道並提供配置元數據,請把 @Pipe 裝飾器應用到這個類上
建立管道命令 ng g p 管道名稱
管道示例

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'exponentialStrength'})
export class ExponentialStrengthPipe implements PipeTransform {
  transform(value: number, exponent = 1): string {
    if(valuev === 0){
        return '男';
    }else {
      return '女';
    }
}

如果是原始類型的輸入值,比如 String 或 Number ,或者是對象引用型的輸入值,比如 Date 或 Array ,那麼每當 Angular 檢測到輸入值或引用有變化時,就會執行該輸入管道。同樣,數組和對象中的值變化時不能檢測到。解決辦法可以使用新的數組或對象代替原來的對象或數組。

檢測複合對象中的非純變更

要在複合對象內部進行更改後執行自定義管道(例如更改數組元素),就需要把管道定義為 impure 以檢測非純的變更。每當按鍵或鼠標移動時,Angular 都會檢測到一次變更,從而執行一個非純管道。

@Pipe({
  name: 'flyingHeroesImpure',
  pure: false
})

當然,不建議使用這種方式,這會大大降低效率。

從一個可觀察對象中解包數據

使用內置的 AsyncPipe 接受一個可觀察對象作為輸入,並自動訂閲輸入。如果沒有這個管道,你的組件代碼就必須訂閲這個可觀察對象來使用它的值,提取已解析的值、把它們公開進行綁定,並在銷燬這段可觀察對象時取消訂閲,以防止內存泄漏。 AsyncPipe 是一個非純管道,可以節省組件中的樣板代碼,以維護訂閲,並在數據到達時持續從該可觀察對象中提供值。

import { Component } from '@angular/core';

import { Observable, interval } from 'rxjs';
import { map, take } from 'rxjs/operators';

@Component({
  selector: 'app-hero-async-message',
  template: `
    <h2>Async Hero Message and AsyncPipe</h2>
    <p>Message: {{ message$ | async }}</p>
    <button (click)="resend()">Resend</button>`,
})
export class HeroAsyncMessageComponent {
  message$: Observable<string>;

  private messages = [
    'You are my hero!',
    'You are the best hero!',
    'Will you be my hero?'
  ];

  constructor() {
    this.message$ = this.getResendObservable();
  }

  resend() {
    this.message$ = this.getResendObservable();
  }

  private getResendObservable() {
    return interval(500).pipe(
      map(i => this.messages[i]),
      take(this.messages.length)
    );
  }
}

異步管道

有時我們寫的管道需要向後台請求數據,這個時候就需要用到異步管道。
異步管道實際上是把返回值類型聲明為Observable,管道接收到輸入值後,向後台請求數據,請求到數據後通過Observable主動向外彈出值,並返回這個值,然後使用時通過上面的AsyncPipe自動訂閲並接收數據。

transform(regionId: number): Observable<string> {
    this.observable = new Observable<string>(subscriber => {
      this.districtService.getDistrictByRegionId(regionId)
        .subscribe(district => {
          subscriber.next(distric);
          subscriber.complete();
        })
      return this.observable;
    }
  }

使用
{{ 數據 | 管道名 | async }}

Angular內置管道

內置管道官方文檔鏈接
DatePipe:根據本地環境中的規則格式化日期值。
UpperCashPipe:把文本全部轉換成大寫。
LowerCashPipe:把文本全部轉換成小寫。
CurrencyPipe:把數字轉換成貨幣字符串,根據本地環境中的規則進行格式化。
DecimalPipe:把數字轉換成帶小數點的字符串,根據本地環境中的規則進行格式化。
PercentPipe:把數字轉換成百分比字符串,根據本地環境中的規則進行格式化。

可以定義樣式的管道

這種比較特殊的管道可以直接返回html代碼,可以在代碼中聲明樣式

transform(input: boolean, ...args: unknown[]): SafeHtml {

    if (!isNotNullOrUndefined(input)){
      return '-';
    }
    let clazz = 'primary';
    let value = '是';
    if (!input) {
      clazz = 'info';
      value = '否'
    }
    return this.domSanitizer.bypassSecurityTrustHtml(`<span class="badge badge-${clazz}">${value}</span>`)
  }

使用

<td [innerHTML]="數據 | trueOrFalse"></td>

效果

總結

管道為我們提供了一種方便的數據轉換的方式,同時可以避免造重複的輪子,需要注意在寫管道時不要忘了對管道輸入數據進行處理,使自己的代碼更加健壯,同時不給隊友挖坑。

説點別的


寫代碼的時候一定要認真!
一定要認真!
一定要認真!
不然就是在坑隊友!
非常抱歉因為我的錯誤坑了學長。

分享一個非常有意思的工具pyautogui
可以用來模擬鼠標的點擊和鍵盤輸入等功能,可以用來寫一些小的腳本。

Add a new Comments

Some HTML is okay.