Angular 18+ 高级教程 – Component 组件 の Pipe 管道
介绍
Pipe 类似于 Template Syntax,它的用途是 transform value for display。
参考:
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,有好几个选择:
'code' 表示显示 currency code
'symbol' 表示显示符号就够了。Angular 会把 code 转成对应的 symbol,比如 USD -> $
'symbol-narrow' 也是显示 symbol 但是是 "narrow" 版,马来西亚的 symbol-narrow 是 'RM' Ringgit Malaysia 的缩写
'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 常用于处理 Promise、RxJS 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 管道的更多相关文章
- python学习笔记——multiprocessing 多进程组件 Pipe管道
进程间通信(IPC InterProcess Communication)是值在不同进程间传播或交换信息. IPC通过有管道(无名管道 和 有名 / 命名管道).消息队列.共享存储 / 内容.信号量. ...
- Angular CLI 使用教程指南参考
Angular CLI 使用教程指南参考 Angular CLI 现在虽然可以正常使用但仍然处于测试阶段. Angular CLI 依赖 Node 4 和 NPM 3 或更高版本. 安装 要安装Ang ...
- vue 基础-->进阶 教程(3):组件嵌套、组件之间的通信、路由机制
前面的nodejs教程并没有停止更新,因为node项目需要用vue来实现界面部分,所以先插入一个vue教程,以免不会的同学不能很好的完成项目. 本教程,将从零开始,教给大家vue的基础.高级操作.组件 ...
- 一篇文章看懂angularjs component组件
壹 ❀ 引 我在 angularjs 一篇文章看懂自定义指令directive 一文中详细介绍了directive基本用法与完整属性介绍.directive是个很神奇的存在,你可以不设置templa ...
- 分享25个新鲜出炉的 Photoshop 高级教程
网络上众多优秀的 Photoshop 实例教程是提高 Photoshop 技能的最佳学习途径.今天,我向大家分享25个新鲜出炉的 Photoshop 高级教程,提高你的设计技巧,制作时尚的图片效果.这 ...
- Python第十一天 异常处理 glob模块和shlex模块 打开外部程序和subprocess模块 subprocess类 Pipe管道 operator模块 sorted函数 os模块 hashlib模块 platform模块 csv模块
Python第十一天 异常处理 glob模块和shlex模块 打开外部程序和subprocess模块 subprocess类 Pipe管道 operator模块 sorted函 ...
- [转帖]tar高级教程:增量备份、定时备份、网络备份
tar高级教程:增量备份.定时备份.网络备份 作者: lesca 分类: Tutorials, Ubuntu 发布时间: 2012-03-01 11:42 ė浏览 27,065 次 61条评论 一.概 ...
- Siki_Unity_2-9_C#高级教程(未完)
Unity 2-9 C#高级教程 任务1:字符串和正则表达式任务1-1&1-2:字符串类string System.String类(string为别名) 注:string创建的字符串是不可变的 ...
- angular里使用vue/vue组件怎么在angular里用
欢迎加入前端交流群交流知识&&获取视频资料:749539640 如何在angularjs(1)中使用vue参考: https://medium.com/@graphicbeacon/h ...
- angularjs中directive指令与component组件有什么区别?
壹 ❀ 引 我在前面花了两篇博客分别系统化介绍了angularjs中的directive指令与component组件,当然directive也能实现组件这点毋庸置疑.在了解完两者后,即便我们知道co ...
随机推荐
- JDBC第二天:防sql攻击
1 什么是SQL攻击 在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句!例如用户在登录时输入的用户名和密码都是为SQL语 ...
- Django model 层之事务管理总结
Django model 层之事务管理总结 by:授客 QQ:1033553122 实践环境 Python版本:python-3.4.0.amd64 下载地址:https://www.python.o ...
- 2024NOI联合省选游记
人生当中成功只是一时的,而失败却是主旋律. 不太好的的阅读体验 本文作者:xxxalq 所谓游记,顾名思义就是指游玩所记,所以重点在玩而不在省选. 由于没有参加 \(\text{NOIP}\),导致我 ...
- android常用布局基础学习
总结:可水平放置可垂直放置也可穿插使用,默认为水平 <!--我在第一次使用权重的时候忽视了本线性布局中的宽度与高度,如果要使用权重,请将线性布局的最初大小设置为match_parent,否则不会 ...
- 写写Redis十大类型bitmap的常用命令
其实这些命令官方上都有,而且可读性很强,还有汉化组翻译的http://redis.cn/commands.html,不过光是练习还是容易忘,写一写博客记录一下 bitmap 位图,是由0和1状态表现的 ...
- docker redis集群实验
集群redis 分片+高可用+负载均衡 master + slave{1..5} 一个挂了另一个顶上 通过脚本创建6个redis配置文件 [root@docker ~]# for port in $( ...
- python面向对象游戏练习:好人坏人手枪手榴弹
python面向对象游戏练习:好人坏人手枪手榴弹 主要是多态的练习,对象作为参数传给方法使用 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 ...
- mujoco安装报错:mujoco_py/cymj.pyx:67:5: Exception check on 'c_warning_callback' will always require the GIL to be acquired.
参考: https://blog.csdn.net/weixin_49373427/article/details/131981583 https://blog.csdn.net/CCCDeric/a ...
- ubuntu22.04 终端显示数字剑雨
数字剑雨是读大学时候常用的屏保,这些年基本也再没有用过,不经意间想到了这个曾经的屏保,发现Ubuntu原版的桌面系统是没有屏保的,又不想换桌面系统,想想还是单独安装一下这个数字剑雨吧. 在Ubuntu ...
- Spring Boot 基于 SCRAM 认证集成 Kafka 的详解
一.说明 在现代微服务架构中,Kafka 作为消息中间件被广泛使用,而安全性则是其中的一个关键因素.在本篇文章中,我们将探讨如何在 Spring Boot 应用中集成 Kafka 并使用 SCRAM ...