管道 #
一、管道概述 #
管道用于在模板中转换数据,将数据格式化为用户友好的形式。
html
<p>{{ birthday | date }}</p>
<p>{{ price | currency }}</p>
<p>{{ name | uppercase }}</p>
二、内置管道 #
2.1 日期管道 #
html
<p>{{ birthday | date }}</p>
<p>{{ birthday | date:'short' }}</p>
<p>{{ birthday | date:'long' }}</p>
<p>{{ birthday | date:'fullDate' }}</p>
<p>{{ birthday | date:'yyyy-MM-dd' }}</p>
<p>{{ birthday | date:'MM/dd/yyyy' }}</p>
<p>{{ birthday | date:'h:mm a' }}</p>
2.2 数字管道 #
html
<p>{{ 1234.56 | number }}</p>
<p>{{ 1234.56 | number:'1.0-0' }}</p>
<p>{{ 1234.56 | number:'1.2-2' }}</p>
<p>{{ 0.259 | percent }}</p>
<p>{{ 0.259 | percent:'1.0-2' }}</p>
2.3 货币管道 #
html
<p>{{ 1234.56 | currency }}</p>
<p>{{ 1234.56 | currency:'CNY' }}</p>
<p>{{ 1234.56 | currency:'USD':'symbol' }}</p>
<p>{{ 1234.56 | currency:'CNY':'symbol':'1.0-2' }}</p>
<p>{{ 1234.56 | currency:'CNY':'symbol-narrow' }}</p>
2.4 大小写管道 #
html
<p>{{ 'hello world' | uppercase }}</p>
<p>{{ 'HELLO WORLD' | lowercase }}</p>
<p>{{ 'hello world' | titlecase }}</p>
2.5 JSON管道 #
html
<pre>{{ user | json }}</pre>
2.6 Slice管道 #
html
<p>{{ 'Hello World' | slice:0:5 }}</p>
<p>{{ [1, 2, 3, 4, 5] | slice:1:4 }}</p>
2.7 异步管道 #
typescript
@Component({
template: `
<p>{{ data$ | async }}</p>
<p>{{ user$ | async?.name }}</p>
`
})
export class ExampleComponent {
data$ = of('Hello');
user$ = this.http.get<User>('/api/user');
}
2.8 I18n管道 #
html
<p>{{ date | date:'medium':'':'zh-CN' }}</p>
<p>{{ 1234.56 | currency:'CNY':'symbol':'1.2-2':'zh-CN' }}</p>
三、链式管道 #
html
<p>{{ message | uppercase | slice:0:20 }}</p>
<p>{{ price | currency:'CNY' | uppercase }}</p>
<p>{{ birthday | date:'fullDate' | uppercase }}</p>
四、自定义管道 #
4.1 创建管道 #
bash
ng generate pipe pipes/truncate
4.2 管道实现 #
typescript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit: number = 20, suffix: string = '...'): string {
if (!value) return '';
if (value.length <= limit) {
return value;
}
return value.substring(0, limit) + suffix;
}
}
4.3 使用管道 #
typescript
import { TruncatePipe } from './pipes/truncate.pipe';
@Component({
selector: 'app-example',
standalone: true,
imports: [TruncatePipe],
template: `
<p>{{ longText | truncate }}</p>
<p>{{ longText | truncate:50 }}</p>
<p>{{ longText | truncate:30:'...' }}</p>
`
})
export class ExampleComponent {
longText = '这是一段很长的文本内容,需要进行截断处理';
}
五、实用自定义管道 #
5.1 安全HTML管道 #
typescript
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Pipe({
name: 'safeHtml',
standalone: true
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(value: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
html
<div [innerHTML]="htmlContent | safeHtml"></div>
5.2 过滤管道 #
typescript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filter',
standalone: true
})
export class FilterPipe implements PipeTransform {
transform<T>(items: T[], field: keyof T, value: any): T[] {
if (!items || !field || !value) {
return items;
}
return items.filter(item =>
String(item[field]).toLowerCase().includes(String(value).toLowerCase())
);
}
}
html
<ul>
<li *ngFor="let user of users | filter:'name':searchTerm">
{{ user.name }}
</li>
</ul>
5.3 排序管道 #
typescript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'sortBy',
standalone: true
})
export class SortByPipe implements PipeTransform {
transform<T>(items: T[], field: keyof T, order: 'asc' | 'desc' = 'asc'): T[] {
if (!items || !field) {
return items;
}
const sorted = [...items].sort((a, b) => {
const aVal = a[field];
const bVal = b[field];
if (aVal < bVal) return -1;
if (aVal > bVal) return 1;
return 0;
});
return order === 'desc' ? sorted.reverse() : sorted;
}
}
html
<ul>
<li *ngFor="let user of users | sortBy:'name':'asc'">
{{ user.name }}
</li>
</ul>
5.4 文件大小管道 #
typescript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'fileSize',
standalone: true
})
export class FileSizePipe implements PipeTransform {
transform(bytes: number, decimals: number = 2): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
}
}
html
<p>{{ 1024 | fileSize }}</p>
<p>{{ 1048576 | fileSize }}</p>
5.5 时间格式管道 #
typescript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'timeAgo',
standalone: true
})
export class TimeAgoPipe implements PipeTransform {
transform(value: Date | string): string {
const date = new Date(value);
const now = new Date();
const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);
const intervals = {
年: 31536000,
月: 2592000,
周: 604800,
天: 86400,
小时: 3600,
分钟: 60
};
for (const [unit, secondsInUnit] of Object.entries(intervals)) {
const interval = Math.floor(seconds / secondsInUnit);
if (interval >= 1) {
return `${interval}${unit}前`;
}
}
return '刚刚';
}
}
html
<p>{{ createdAt | timeAgo }}</p>
六、纯管道与非纯管道 #
6.1 纯管道(默认) #
typescript
@Pipe({
name: 'purePipe',
pure: true // 默认值
})
export class PurePipe implements PipeTransform {
transform(value: any) {
console.log('纯管道执行');
return value;
}
}
特点:
- 只在输入值变化时执行
- 性能更好
- 适用于纯函数
6.2 非纯管道 #
typescript
@Pipe({
name: 'impurePipe',
pure: false
})
export class ImpurePipe implements PipeTransform {
transform(value: any) {
console.log('非纯管道执行');
return value;
}
}
特点:
- 每次变更检测都执行
- 性能较差
- 适用于需要频繁更新的场景
6.3 非纯管道示例 #
typescript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filterArray',
pure: false
})
export class FilterArrayPipe implements PipeTransform {
transform<T>(items: T[], predicate: (item: T) => boolean): T[] {
return items.filter(predicate);
}
}
七、管道最佳实践 #
7.1 使用纯管道 #
typescript
// 推荐:纯管道
@Pipe({
name: 'truncate',
pure: true
})
// 谨慎使用:非纯管道
@Pipe({
name: 'filter',
pure: false
})
7.2 避免复杂计算 #
typescript
// 不推荐:复杂计算
@Pipe({ name: 'complex' })
export class ComplexPipe implements PipeTransform {
transform(value: any) {
// 复杂计算...
return result;
}
}
// 推荐:预先计算
this.formattedData = this.formatData(this.rawData);
7.3 缓存结果 #
typescript
@Pipe({
name: 'expensive',
pure: true
})
export class ExpensivePipe implements PipeTransform {
private lastInput: any;
private lastResult: any;
transform(value: any) {
if (value === this.lastInput) {
return this.lastResult;
}
this.lastInput = value;
this.lastResult = this.expensiveCalculation(value);
return this.lastResult;
}
private expensiveCalculation(value: any) {
// 复杂计算
}
}
八、总结 #
| 管道 | 说明 |
|---|---|
date |
日期格式化 |
number |
数字格式化 |
currency |
货币格式化 |
uppercase |
大写转换 |
lowercase |
小写转换 |
titlecase |
标题大小写 |
json |
JSON格式化 |
slice |
数组/字符串截取 |
async |
异步数据绑定 |
| 自定义管道 | 自定义转换逻辑 |
下一步:动态组件
最后更新:2026-03-26