介绍

Pipe 类似于 Template Syntax,它的用途是 transform value for display。

参考:

Docs – Understanding Pipes

DatePipe

一个简单的例子。

我有一个 JavaScript 的 Date value,我要 display 给用户看,那你不可能直接 .toString() 就显示嘛,很丑丫。

所以呢,它就需要一个 transformation。而按照职责划分(Thinking in Angular Way),这个任务显然是属于 view 的 logic。

所以应该在 HTML 去表达。于是就有了 Pipe 写法。

<h1>{{ today }}</h1>
<h1>{{ today | date : 'dd MMM yyyy' }}</h1>
<h1>{{ today | date : 'fullDate' }}</h1>

pipe 的语法是这样的 {{  value | pipeName : paramter1 : paramter2  }}

你可以把它看作是一个 function call。

比如现在我们使用的 DatePipe,就是 const displayDate = date(today , 'dd MMM yyyy');

today 是 component property,是一个 new Date()

| pipe 就是启动 pipe transform。

date 是 Angular build-in 的 DatePipe,Angular build-in 了许多 pipe,每一个负责不同的 transform,顾名思义 DatePipe 自然是用于 transform date value。

注:要使用 Angular build-in 的 Pipe,必须在 Component metadata imports CommonModule 哦。

: 分号表示要输入 paramters

'dd MMM yyyy' 则是输入的 parameter,声明想 transform to 什么 date format。(p.s. 想知道所有 Angular 支持的 format, 参考这里

效果

UpperCasePipe, LowerCasePipe, TitleCase

<h1>{{ 'Hello World' | uppercase }}</h1>
<h1>{{ 'Hello World' | lowercase }}</h1>
<h1>{{ 'hello world' | titlecase }}</h1>

效果

DecimalPipe

在 JavaScript, 我们可以用下划线来分割 number 让它好看一点

<h1>{{ 1_000_000 }}</h1>

但当渲染 HTML 的时候,它会被 number.toString(),结果变成

DecimalPipe 可用于解决这种问题。

<h1>{{ 1_000_000 | number }}</h1>

注:虽然它叫 DecimalPipe,但使用时是 | number 哦。

效果

除此之外,number 还支持一个 digit setting,

它可以控制小数点前后号码,最少最多几个数字。

语法是

{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}

for example '2.2-4' 表示小数点前最少要 2 digit,小数点后最少 2 最多 4 个 digit。

不够 digit 时它会用零补上,超过 digit 时它会四舍五入进位.

<h1>{{ 1.10 | number : '2.2-4' }}</h1>   <!--01.10 前面补上了一个 0 -->
<h1>{{ 0.1 | number : '.2-4' }}</h1> <!--0.10 后面补上了一个 0-->
<h1>{{ .123 | number : '1.2-4' }}</h1> <!--0.123 前面补上了一个 0-->
<h1>{{ .12345 | number : '1.2-4' }}</h1> <!--0.1235 后面四舍五入进位-->

注:它的 default 是 '1.0-3'。另外,小数点前只能控制最少 digit,不能控制最多。

PercentPipe

PercentPipe 的作用时把 0.57 变成 '57%'

<h1>{{ 0.57 | percent }}</h1>

效果

它也支持 digit setting

<h1>{{ 0.575 | percent : '.0' }}</h1> <!--58%-->

p.s. '.0' 相等于 '1.0-0',best practice 是写完整的 '1.0-0'。

CurrencyPipe

CurrentPipe 会 transform number 变成带有 current code。

<h1>{{ 100 | currency : 'USD' }}</h1>                   <!-- $100.00 默认是显示 symbol 哦 -->
<h1>{{ 100 | currency : 'USD' : 'code' }}</h1> <!-- USD100.00 -->
<h1>{{ 100 | currency : 'USD' : 'symbol' }}</h1> <!-- $100.00 -->
<h1>{{ 100 | currency : 'MYR' : 'symbol-narrow' }}</h1> <!-- RM100.00 -->
<h1>{{ 100 | currency : 'MYR' : 'M$ ' }}</h1> <!-- M$100.00 -->

第一个参数是 currency code ISO 4217

第二个参数是 display mode,有好几个选择:

  1. 'code' 表示显示 currency code

  2. 'symbol' 表示显示符号就够了。Angular 会把 code 转成对应的 symbol,比如 USD -> $

  3. 'symbol-narrow' 也是显示 symbol 但是是 "narrow" 版,马来西亚的 symbol-narrow 是 'RM' Ringgit Malaysia 的缩写

  4. 'whatever string',如果 code, symbol, symbol-narrow 都不是你要的,那可以提供一个 string 作为 display。

第三个参数是 digit setting,默认是 '1.2-2'。

Global override default currency

default currency 是 USD,我们可以通过 Dependancy Injection 的方式提供一个全局 currency 替换掉 default currency。

import { DEFAULT_CURRENCY_CODE, type ApplicationConfig } from '@angular/core';

export const appConfig: ApplicationConfig = {
providers: [{ provide: DEFAULT_CURRENCY_CODE, useValue: 'MYR' }],
};

JsonPipe, SlicePipe, AsyncPipe

其它 build-in pipes.

<h1>{{ { name: 'Derrick' } | json }}</h1> <!-- { "name": "Derrick" } -->
<h1>{{ ['a', 'b', 'c', 'd'] | slice : 1 : -1 }}</h1> <!-- ['b', 'c'] -->
<h1>{{ value$ | async }}</h1> <!-- value1---value2---value3 -->

async pipe 常用于处理 PromiseRxJS Stream

它内部会 subscribe 和自动 unsubscribe Observable 非常方便。

当 Observable 处于未发布的时候,async pipe 会先返回 null 作为初始值。

Global Configuration

上面例子中有些 Pipe 使用时需要传入 parameters。比如 | currency : 'USD', | date : 'dd MMM yyyy'。

许多时候整个项目的 currency、date format 都是一致的。这时就需要一个 global config。

Pipe 的 global config 是利用 DI 来实现的。

如果想设置全局,可以到 app.config.ts 写入 provider 就可以了。

import { DATE_PIPE_DEFAULT_OPTIONS, DatePipeConfig } from '@angular/common';
import { ApplicationConfig, DEFAULT_CURRENCY_CODE } from '@angular/core'; export const appConfig: ApplicationConfig = {
providers: [
{ provide: DEFAULT_CURRENCY_CODE, useValue: 'USD' },
{
provide: DATE_PIPE_DEFAULT_OPTIONS,
useValue: {
dateFormat: 'dd MMM yyyy',
timezone: '+0800', // if empty string, then Angular will use end-user's local system timezone
} satisfies DatePipeConfig,
},
],
};

DEFAULT_CURRENCY_CODE 和 DATE_PIPE_DEFAULT_OPTIONS 是 InjectionToken

Use Pipe Transform in Any Where

大部分 Angular pipe 都提供了底层方法,所以可以用在任何地方

import { formatDate, formatCurrency, formatNumber, formatPercent} from '@angular/common';

console.log(formatDate(new Date(), 'dd MMM yyyy', 'en-US')); // 06 Apr 2023
console.log(formatCurrency(100, 'en-US', 'RM', 'MYR')); // RM100.00

当然,它们不在 DI 的 cover 范围,也就无法使用 global config 了。

如果想在组件内使用 pipe,可以通过 DI

DatePipe by default 是没有在 DI 中的,所以我们需要 provide。

可以在 app.config.ts provide,也可以通过 Component metadata provide(区别是什么,我会在接下来章节讲解,这里不展开)

然后注入就可以使用了。这样它就能使用到 global config 了。

Custom Pipe

上面提及的都是 Angular build-in 的 pipe。虽然挺多的,但在真实项目中依然会不够用。

幸好,Angular 允许我们自定义 Pipe。(Angular build-in 的 pipe 也是用同一种方式添加进项目的哦)

我们尝试做一个 AgoPipe

CLI command

ng g p ago

p for pipe

一开始长这样

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

@Pipe({
name: 'ago',
standalone: true
})
export class AgoPipe implements PipeTransform {
transform(value: unknown, ...args: unknown[]): unknown {
return null;
}
}

接着我们加入逻辑

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

// 如果有需要 global config
export interface AgoPipeConfig {}
export const AGO_PIPE_CONFIG_TOKEN = new InjectionToken<AgoPipeConfig>(
'AgoPipeConfig'
);
// 底层方法
export function formatAgo(
date: Date,
param1?: string,
config: AgoPipeConfig | null = null
) {
console.log([date, param1, config]); // value, parameter, config
// do any transformation (这里我省略掉具体实现方法)
return '7 days ago';
} @Pipe({
name: 'ago',
standalone: true,
})
export class AgoPipe implements PipeTransform {
private agoPipeConfig = inject(AGO_PIPE_CONFIG_TOKEN, { optional: true }); // 注入 global config transform(date: Date, param1?: string): string {
// 调用底层方法
return formatAgo(date, param1, this.agoPipeConfig);
}
}

看注释理解,里面包含了 global config 和底层方法。类似 Angular 的 formatCurrency 和 DEFAULT_CURRENCY_CODE

在 app.config.ts 提供 global config

import { ApplicationConfig } from '@angular/core';
import { AgoPipeConfig, AGO_PIPE_CONFIG_TOKEN } from './ago.pipe'; export const appConfig: ApplicationConfig = {
providers: [
{ provide: AGO_PIPE_CONFIG_TOKEN, useValue: {} satisfies AgoPipeConfig },
],
};

在组件 imports AgoPipe

@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, AgoPipe], // imports AgoPipe
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
constructor() {}
today = new Date();
}

BTW, Angular build-in 的 pipe 是封装在 CommonModule 里的。

最后,在 template 使用

<h1>{{ today | ago }}</h1>

这样就可以了。

Pure

@Pipe({
name: 'ago',
standalone: true,
pure: false
})

pure 是 Pipe 的一个 config。默认是 true。它表示只有当 value 改变时才需要重新运行 transform 方法。

这个规则在某一些情况是不对的,比如 transform 依赖 config 的时候。因为不只是 value 改变会影响 transform 的结果,config 改变也可能影响 transform 的结果。

所以在这个情况下,我们需要把 pure 设置成 false。设置成 false 以后,不仅仅是当 value 改变,只要当前的组件 re-render(DoCheck 执行不代表 re-render 哦,要 dirty 才会 re-render),transform 就会执行。

至于这个 re-render 是什么概念,我会在后面 Change Detection 章节详细讲解。

Override Built-in Pipe

built-in pipe 很好,但也不是万能的,遇到不合适的场景还是需要魔改一下。这里提供一些魔改方案。

让 CurrencyPipe 支持 Big.js

CurrencyPipe 只支持 number | string | null | undefined

假如我的 value 类型是 Big.js 的 Big 对象,那就不能直接使用了。

最直接的解决方法就是调用 Big.toNumber 把 Big 对象转换成 number 类型。

<h1>{{ price.toNumber() | currency : 'MYR' : 'symbol-narrow' : '.2-2' }}</h1>

不过每次都要调用就很烦啊,我们能不能让 current pipe 支持 Big 对象,在调用 toNumber 封装起来?

可以,直接继承 CurrencyPipe 然后 override transform 方法

@Pipe({
name: 'currency',
standalone: true,
})
export class MyCurrencyPipe extends CurrencyPipe implements PipeTransform {
override transform(
value: number | Decimal | string,
currencyCode?: string,
display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean,
digitsInfo?: string,
locale?: string,
): string | null;
override transform(
value: null | Decimal | undefined,
currencyCode?: string,
display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean,
digitsInfo?: string,
locale?: string,
): null;
override transform(
value: number | Decimal | string | null | undefined,
currencyCode?: string,
display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean,
digitsInfo?: string,
locale?: string,
): string | null;
override transform(
value: number | Decimal | string | null | undefined,
currencyCode?: string,
display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean,
digitsInfo?: string,
locale?: string,
): string | null {
const convertedValue = value instanceof Decimal ? value.toNumber() : value;
return super.transform(convertedValue, currencyCode, display, digitsInfo, locale);
}
}

transform 方法本来就有很多 overload,所以我们得 override 每一个才行,真麻烦,

接着 imports 就可以了。

效果

没有报错了。

注:Pipe name 用回 'currency' 也不要紧,不会撞名字的。Angular compiler 会优先选择我们定义的 Pipe。

目录

上一篇 Angular 18+ 高级教程 – Component 组件 の Attribute Directives 属性型指令

下一篇 Angular 18+ 高级教程 – Change Detection & Ivy rendering engine

想查看目录,请移步 Angular 18+ 高级教程 – 目录

喜欢请点推荐,若发现教程内容以新版脱节请评论通知我。happy coding

Angular 18+ 高级教程 – Component 组件 の Pipe 管道的更多相关文章

  1. python学习笔记——multiprocessing 多进程组件 Pipe管道

    进程间通信(IPC InterProcess Communication)是值在不同进程间传播或交换信息. IPC通过有管道(无名管道 和 有名 / 命名管道).消息队列.共享存储 / 内容.信号量. ...

  2. Angular CLI 使用教程指南参考

    Angular CLI 使用教程指南参考 Angular CLI 现在虽然可以正常使用但仍然处于测试阶段. Angular CLI 依赖 Node 4 和 NPM 3 或更高版本. 安装 要安装Ang ...

  3. vue 基础-->进阶 教程(3):组件嵌套、组件之间的通信、路由机制

    前面的nodejs教程并没有停止更新,因为node项目需要用vue来实现界面部分,所以先插入一个vue教程,以免不会的同学不能很好的完成项目. 本教程,将从零开始,教给大家vue的基础.高级操作.组件 ...

  4. 一篇文章看懂angularjs component组件

     壹 ❀ 引 我在 angularjs 一篇文章看懂自定义指令directive 一文中详细介绍了directive基本用法与完整属性介绍.directive是个很神奇的存在,你可以不设置templa ...

  5. 分享25个新鲜出炉的 Photoshop 高级教程

    网络上众多优秀的 Photoshop 实例教程是提高 Photoshop 技能的最佳学习途径.今天,我向大家分享25个新鲜出炉的 Photoshop 高级教程,提高你的设计技巧,制作时尚的图片效果.这 ...

  6. Python第十一天 异常处理 glob模块和shlex模块 打开外部程序和subprocess模块 subprocess类 Pipe管道 operator模块 sorted函数 os模块 hashlib模块 platform模块 csv模块

    Python第十一天    异常处理  glob模块和shlex模块    打开外部程序和subprocess模块  subprocess类  Pipe管道  operator模块   sorted函 ...

  7. [转帖]tar高级教程:增量备份、定时备份、网络备份

    tar高级教程:增量备份.定时备份.网络备份 作者: lesca 分类: Tutorials, Ubuntu 发布时间: 2012-03-01 11:42 ė浏览 27,065 次 61条评论 一.概 ...

  8. Siki_Unity_2-9_C#高级教程(未完)

    Unity 2-9 C#高级教程 任务1:字符串和正则表达式任务1-1&1-2:字符串类string System.String类(string为别名) 注:string创建的字符串是不可变的 ...

  9. angular里使用vue/vue组件怎么在angular里用

    欢迎加入前端交流群交流知识&&获取视频资料:749539640 如何在angularjs(1)中使用vue参考: https://medium.com/@graphicbeacon/h ...

  10. angularjs中directive指令与component组件有什么区别?

     壹 ❀ 引 我在前面花了两篇博客分别系统化介绍了angularjs中的directive指令与component组件,当然directive也能实现组件这点毋庸置疑.在了解完两者后,即便我们知道co ...

随机推荐

  1. 扬州万方:基于申威平台的 Curve 块存储在高性能和超融合场景下的实践

    背景 扬州万方科技股份有限公司主要从事通信.计算机和服务器.智能车辆.基础软件等产品的科研生产,是国家高新技术企业.专精特新小巨人企业.国家火炬计划承担单位. 业务介绍 申威处理器是在国家" ...

  2. Django使用 DoesNotExist 异常和 Logger 来记录异常情况

    代码不仅处理了特定的异常类型,还可以添加更多的调试信息来帮助诊断问题.可以使用 DoesNotExist 异常和 Logger 来记录异常情况. from django.core.exceptions ...

  3. [oeasy]python0022_框架标题的制作_banner_结尾字符串_end

    ​ 结尾字符串(end) 回忆上次内容 ​python3​​ 的程序是一个 5.3M 的可执行文件 ​​python3​​ 里面存的是 cpu 指令 可以执行的那种 我们可以把指令对应的汇编找到 ​​ ...

  4. oeasy教您玩转vim - 81 - # 宏macro的进阶

    ​ 宏的进阶 macro 回忆 关于宏,上次有4个要点 qa 开始录制宏 q 结束录制宏 @a 应用宏 qA 追加录制宏 甚至可以编辑宏 "ap 把宏作为文本粘贴出来 编辑之后 " ...

  5. Odoo 菜单定义和修改学习总结

    odoo菜单定义和修改学习总结 环境 odoo-14.0.post20221212.tar 定义菜单 方式1: <?xml version="1.0"?> <od ...

  6. Intent 显示与隐式了解认识

    显示Intent 用于精确匹配,指定跳转目标 1.在intent构造函数中调用 Intent intent = new Intent(this,XX.class); 2.调用意图对象的setClass ...

  7. Java基础学习知识点框架(详细)

    //学习网站 Java研发技术学习路线_飞月程序人生-CSDN博客_java开发学习路线 Java后端技术栈梳理 - 知乎 harrywfl/JavaGuide: [Java学习+面试指南] 一份涵盖 ...

  8. 03 OLED显示屏实现

    目录 前言 一.软件模拟IIC协议 1.开启IIC协议 2.结束IIC协议 3.传输数据 二.OLED的操作 1.传输数据的准备 2.写入命令 3.写入数据 4.初始化函数 5.设置光标 6.显示字符 ...

  9. (HASEE)神州笔记本 还原手册 —— 笔记本系统还原

    新买了一个笔记本,神州笔记本(HASEE),随机所带的手册,为防止丢失故把内容记录下来. 开机时按:CTRL + H 进入还原界面,点击"系统还原",点击"恢复出厂备份& ...

  10. 【转载】 Integrating New Games into Retro Gym

    https://medium.com/aureliantactics/integrating-new-games-into-retro-gym-12b237d3ed75 OpenAI's retro ...