问题

在写活动管理详情的时候不知道怎么用内置的日期管道,自己写了一个管道,同时在管道使用时遇到问题。

查看后发现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
可以用来模拟鼠标的点击和键盘输入等功能,可以用来写一些小的脚本。

03-05 23:35