介绍

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. 微信小程序车牌键盘输入组件(支持单个删除更改,支持赋值,支持新能源)

    网上一搜一大堆类似但大多都相对简单,适用的场景并不多.多数也不支持赋值 不支持单个删除更改 我就借鉴了以下文章的思路,为了达到自己想要的效果做了相对应的更改. 借鉴文章链接:> https:// ...

  2. windows服务开发demo

    0.写在前面 windows7开始,windows服务运行在session 0, 用户程序都运行在session x (x >= 1) 而session之间是有隔离的,实践发现是无法在服务中直接 ...

  3. SUM_ACM-Codeforces Round 941 (Div. 2)

    A Card Exchange https://codeforces.com/contest/1966/problem/A 思路:找规律,如果b>a,输出a,如果a中有大于等于b个数,输出b-1 ...

  4. 如何用 WinDbg 调试Linux上的 .NET程序

    一:背景 1. 讲故事 最新版本 1.2402.24001.0 的WinDbg真的让人很兴奋,可以将自己伪装成 GDB 来和远程的 GDBServer 打通来实现对 Linux 上 .NET程序进行调 ...

  5. ScaleDet:AWS 基于标签相似性提出可扩展的多数据集目标检测器 | CVPR 2023

    论文提出了一种可扩展的多数据集目标检测器(ScaleDet),可通过增加训练数据集来扩大其跨数据集的泛化能力.与现有的主要依靠手动重新标记或复杂的优化来统一跨数据集标签的多数据集学习器不同,论文引入简 ...

  6. Cloudflare教程:如何注册账户、购买域名、开启免费CDN服务?

    Cloudflare介绍 什么是Cloudflare Cloudflare是一家总部位于旧金山的美国跨国科技企业,以向客户提供基于反向代理的内容分发网络(CDN)及分布式域名解析服务为主要业务. 目前 ...

  7. ComfyUI插件:ComfyUI Impact 节点(二)

    前言: 学习ComfyUI是一场持久战,而 ComfyUI Impact 是一个庞大的模块节点库,内置许多非常实用且强大的功能节点 ,例如检测器.细节强化器.预览桥.通配符.Hook.图片发送器.图片 ...

  8. 【SQL】SQL训练网站 SQLBlot

    网站地址: https://sqlbolt.com/ Lesson1: -- https://sqlbolt.com/lesson/select_queries_introduction -- Fin ...

  9. 甄嬛霸气照 —— Chinese Queen

  10. 如何理解计算机类论文、机器学习论文、人工智能AI论文中的“soft”和“hard”呢?

    如何理解计算机类论文.机器学习论文.人工智能AI论文中的"soft"和"hard"呢? 最近在看论文中总看到带有"soft"和"h ...