05_核心语法:模板与组件基础
核心语法:模板与组件基础
模板与组件是Angular应用的核心构建块。Angular v20引入了全新的模板语法和组件特性,旨在提升开发效率与应用性能。本章将详细讲解这些新特性,包括现代模板语法、组件的核心构成要素、指令系统以及管道的使用,帮助你建立Angular开发的基础认知。
1. 全新模板语法(v20推荐标准)
Angular v20推出了基于@符号的新一代模板语法,替代了传统的结构指令(如*ngIf、*ngFor)。新语法不仅更简洁易读,还带来了更好的类型安全性和性能优化。
条件渲染:@if替代*ngIf,类型收窄与空值处理
@if指令用于根据条件渲染模板内容,相比传统的*ngIf,它提供了更直观的语法和更严格的类型检查。
基本用法:
<!-- 新语法 -->
@if (isLoggedIn) {
<p>欢迎回来,用户!</p>
}
<!-- 旧语法对比 -->
<p *ngIf="isLoggedIn">欢迎回来,用户!</p>
else分支处理:
@if (user) {
<p>用户名:{{ user.name }}</p>
} @else {
<p>请登录</p>
}
@if的显著优势是自动类型收窄,当检查对象是否存在时,Angular模板会自动识别对象内部属性的可用性:
@if (user) {
<!-- 此处TypeScript已知user不为null/undefined -->
<p>年龄:{{ user.age }}</p>
} @else {
<p>用户信息不存在</p>
}
循环渲染:@for与@empty空状态
@for指令用于遍历集合数据并渲染列表,替代了传统的*ngFor,强制要求指定跟踪标识(track)以优化性能。
基本用法:
@for (product of products; track product.id) {
<div class="product">
<h3>{{ product.name }}</h3>
<p>价格:{{ product.price }}</p>
</div>
}
循环变量:
@for (item of items; track item.id; let i = $index; let first = $first) {
<div class="item {{ first ? 'first' : '' }}">
第{{ i + 1 }}项:{{ item.name }}
</div>
}
空状态处理:
@for (message of messages; track message.id) {
<div class="message">{{ message.content }}</div>
} @empty {
<div class="no-messages">暂无消息</div>
}
变量声明:@let简化深层属性访问与异步数据订阅
@let指令允许在模板中声明变量,特别适合处理深层嵌套属性和异步数据:
@let fullName = user?.firstName + ' ' + user?.lastName;
<p>全名:{{ fullName }}</p>
<!-- 处理异步数据 -->
@let user = user$ | async;
@if (user) {
<p>姓名:{{ user.name }}</p>
}
2. 指令系统:扩展模板功能
指令是Angular中用于扩展HTML元素功能的特殊类,分为属性指令(修改元素属性)和结构指令(修改DOM结构)两类。
2.1 内置指令
Angular提供了多个常用内置指令:
属性指令:
-
ngClass:动态添加CSS类<div [ngClass]="{ 'active': isActive, 'disabled': isDisabled }"></div> -
ngStyle:动态设置样式<p [ngStyle]="{ 'color': textColor, 'font-size': fontSize + 'px' }"></p> -
ngModel:表单双向绑定(需导入FormsModule)<input type="text" [(ngModel)]="username">
结构指令:
除了前面介绍的@if、@for,还有@switch用于多条件分支:
@switch (status) {
@case ('success') {
<p class="success">操作成功</p>
}
@case ('error') {
<p class="error">操作失败</p>
}
@default {
<p>等待操作</p>
}
}
2.2 自定义指令
创建自定义指令可以封装可复用的DOM操作逻辑。
创建属性指令:
import { Directive, ElementRef, Input, OnInit } from '@angular/core';
@Directive({
selector: '[appHighlight]',
standalone: true
})
export class HighlightDirective implements OnInit {
// 接收输入参数
@Input() highlightColor = 'yellow';
constructor(private el: ElementRef) {}
ngOnInit() {
// 修改宿主元素样式
this.el.nativeElement.style.backgroundColor = this.highlightColor;
}
}
使用自定义指令:
<!-- 在模板中使用 -->
<p appHighlight>默认黄色高亮</p>
<p appHighlight [highlightColor]="'lightblue'">蓝色高亮</p>
与Signals结合:
import { Directive, ElementRef, effect } from '@angular/core';
import { signal } from '@angular/core';
@Directive({
selector: '[appScrollSpy]',
standalone: true
})
export class ScrollSpyDirective {
scrollPosition = signal(0);
constructor(private el: ElementRef) {
// 监听滚动事件
window.addEventListener('scroll', () => {
this.scrollPosition.set(window.scrollY);
});
// 响应式更新样式
effect(() => {
if (this.scrollPosition() > 100) {
this.el.nativeElement.classList.add('scrolled');
} else {
this.el.nativeElement.classList.remove('scrolled');
}
});
}
}
3. 管道:数据转换与格式化
管道(Pipe)用于在模板中转换数据格式,Angular提供了多种内置管道,并支持创建自定义管道。
3.1 内置管道
常用内置管道:
-
DatePipe:日期格式化<p>当前时间:{{ today | date:'yyyy-MM-dd HH:mm:ss' }}</p> -
UpperCasePipe/LowerCasePipe:大小写转换<p>{{ 'hello' | uppercase }}</p> <!-- 输出 HELLO --> -
CurrencyPipe:货币格式化<p>{{ price | currency:'CNY':'symbol' }}</p> <!-- 输出 ¥100.00 --> -
AsyncPipe:处理异步数据(自动订阅和取消订阅)<p>{{ user$ | async | json }}</p>
3.2 自定义管道
创建自定义管道实现特定数据转换逻辑:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate',
standalone: true,
pure: true // 纯管道,仅在输入变化时重新计算
})
export class TruncatePipe implements PipeTransform {
// value: 输入值,args: 额外参数
transform(value: string, maxLength: number = 10, suffix: string = '...'): string {
if (value.length <= maxLength) return value;
return value.slice(0, maxLength) + suffix;
}
}
使用自定义管道:
<!-- 在模板中使用 -->
<p>{{ longText | truncate:20:'...查看更多' }}</p>
<!-- 与其他管道结合使用 -->
<p>{{ longText | truncate:10 | uppercase }}</p>
非纯管道:
非纯管道(pure: false)会在每次变更检测时重新计算,适合依赖外部状态的数据转换:
@Pipe({
name: 'localTime',
standalone: true,
pure: false // 非纯管道
})
export class LocalTimePipe implements PipeTransform {
transform(timestamp: number): string {
return new Date(timestamp).toLocaleTimeString();
}
}
4. 组件核心构成
组件是Angular应用的基本构建单元,每个组件由模板(Template)、类(Class)和样式(Styles)三部分组成。
4.1 装饰器配置:@Component元数据与独立组件
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HighlightDirective } from './highlight.directive';
import { TruncatePipe } from './truncate.pipe';
@Component({
selector: 'app-user-profile',
standalone: true,
imports: [CommonModule, HighlightDirective, TruncatePipe], // 导入依赖
templateUrl: './user-profile.component.html',
styleUrls: ['./user-profile.component.scss']
})
export class UserProfileComponent {
// 组件逻辑
}
4.2 响应式数据:Signal创建与更新
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-cart',
standalone: true,
template: `
<p>商品总数:{{ totalItems() }}</p>
<p>总价:{{ totalPrice() | currency }}</p>
`
})
export class CartComponent {
items = signal([
{ name: '笔记本', price: 5999, quantity: 1 }
]);
// 计算属性
totalItems = computed(() => {
return this.items().reduce((sum, item) => sum + item.quantity, 0);
});
totalPrice = computed(() => {
return this.items().reduce((sum, item) => sum + (item.price * item.quantity), 0);
});
}
4.3 生命周期钩子:从ngOnInit到ngOnDestroy
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import { interval, Subscription } from 'rxjs';
@Component({
selector: 'app-timer',
standalone: true,
template: `<p>已运行:{{ seconds }}秒</p>`
})
export class TimerComponent implements OnInit, OnDestroy {
@Input() initialSeconds = 0;
seconds = 0;
private timerSubscription?: Subscription;
ngOnInit() {
this.seconds = this.initialSeconds;
this.timerSubscription = interval(1000).subscribe(() => {
this.seconds++;
});
}
ngOnDestroy() {
this.timerSubscription?.unsubscribe();
}
}
通过本章学习,你已经掌握了Angular v20的核心模板语法、指令系统、管道使用以及组件基础。

浙公网安备 33010602011771号