内置指令 #

一、指令概述 #

Angular指令分为三种类型:

类型 说明 示例
组件 带有模板的指令 @Component
结构指令 改变DOM结构 *ngIf, *ngFor
属性指令 改变元素外观或行为 ngClass, ngStyle

二、结构指令 #

2.1 *ngIf #

基本用法:

html
<div *ngIf="isVisible">显示内容</div>
<div *ngIf="!isLoading">加载完成</div>

else分支:

html
<div *ngIf="isLoading; else loaded">
  加载中...
</div>

<ng-template #loaded>
  <div>加载完成</div>
</ng-template>

then-else语法:

html
<div *ngIf="isLoggedIn; then loggedIn; else loggedOut"></div>

<ng-template #loggedIn>
  <p>欢迎回来!</p>
</ng-template>

<ng-template #loggedOut>
  <p>请先登录</p>
</ng-template>

结合async管道:

html
<div *ngIf="user$ | async as user; else loading">
  <p>用户名: {{ user.name }}</p>
</div>

<ng-template #loading>
  <p>加载中...</p>
</ng-template>

2.2 *ngFor #

基本用法:

html
<ul>
  <li *ngFor="let item of items">
    {{ item.name }}
  </li>
</ul>

获取索引:

html
<ul>
  <li *ngFor="let item of items; let i = index">
    {{ i + 1 }}. {{ item.name }}
  </li>
</ul>

内置变量:

html
<ul>
  <li *ngFor="let item of items; 
              let i = index; 
              let first = first; 
              let last = last; 
              let even = even; 
              let odd = odd">
    <span *ngIf="first">[首个]</span>
    {{ i + 1 }}. {{ item.name }}
    <span *ngIf="last">[末尾]</span>
  </li>
</ul>
变量 说明
index 当前项索引(从0开始)
first 是否为第一项
last 是否为最后一项
even 索引是否为偶数
odd 索引是否为奇数

trackBy优化:

typescript
@Component({
  template: `
    <li *ngFor="let item of items; trackBy: trackById">
      {{ item.name }}
    </li>
  `
})
export class ExampleComponent {
  items = [
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
    { id: 3, name: 'Item 3' }
  ];
  
  trackById(index: number, item: Item): number {
    return item.id;
  }
}

嵌套循环:

html
<div *ngFor="let category of categories">
  <h3>{{ category.name }}</h3>
  <ul>
    <li *ngFor="let product of category.products">
      {{ product.name }}
    </li>
  </ul>
</div>

2.3 *ngSwitch #

基本用法:

html
<div [ngSwitch]="status">
  <p *ngSwitchCase="'active'">激活状态</p>
  <p *ngSwitchCase="'inactive'">未激活状态</p>
  <p *ngSwitchCase="'pending'">待审核</p>
  <p *ngSwitchDefault>未知状态</p>
</div>

复杂示例:

typescript
@Component({
  template: `
    <div [ngSwitch]="user.role">
      <app-admin-dashboard *ngSwitchCase="'admin'"></app-admin-dashboard>
      <app-user-dashboard *ngSwitchCase="'user'"></app-user-dashboard>
      <app-guest-view *ngSwitchDefault></app-guest-view>
    </div>
  `
})
export class DashboardComponent {
  @Input() user: User;
}

三、属性指令 #

3.1 ngClass #

对象语法:

html
<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">
  内容
</div>

数组语法:

html
<div [ngClass]="['class1', 'class2', 'class3']">
  内容
</div>

字符串语法:

html
<div [ngClass]="'active highlighted'">
  内容
</div>

动态类名:

typescript
@Component({
  template: `
    <div [ngClass]="getClassNames()">内容</div>
  `
})
export class ExampleComponent {
  isActive = true;
  isHighlighted = false;
  
  getClassNames() {
    return {
      'active': this.isActive,
      'highlighted': this.isHighlighted,
      'text-bold': true
    };
  }
}

结合条件:

html
<div [ngClass]="{
  'status-active': status === 'active',
  'status-inactive': status === 'inactive',
  'status-pending': status === 'pending'
}">
  {{ status }}
</div>

3.2 ngStyle #

对象语法:

html
<div [ngStyle]="{'color': 'red', 'font-size': '16px'}">
  内容
</div>

动态样式:

html
<div [ngStyle]="{
  'color': isActive ? 'green' : 'gray',
  'font-size': fontSize + 'px',
  'background-color': bgColor
}">
  动态样式内容
</div>

使用组件属性:

typescript
@Component({
  template: `
    <div [ngStyle]="divStyles">内容</div>
  `
})
export class ExampleComponent {
  divStyles = {
    'color': 'white',
    'background-color': 'blue',
    'padding': '20px',
    'border-radius': '8px'
  };
}

条件样式:

html
<div [ngStyle]="{
  'background-color': isLoading ? '#f0f0f0' : '#ffffff',
  'opacity': isLoading ? 0.5 : 1
}">
  <p *ngIf="!isLoading">内容加载完成</p>
  <p *ngIf="isLoading">加载中...</p>
</div>

四、Angular 17+ 新控制流语法 #

4.1 @if语法 #

html
@if (isVisible) {
  <div>显示内容</div>
}

@if (isLoading) {
  <div>加载中...</div>
} @else {
  <div>加载完成</div>
}

@if (score >= 90) {
  <p>优秀</p>
} @else if (score >= 60) {
  <p>及格</p>
} @else {
  <p>不及格</p>
}

4.2 @for语法 #

html
@for (item of items; track item.id) {
  <li>{{ item.name }}</li>
}

@for (item of items; track item.id; let i = $index, let first = $first) {
  <li [class.first]="first">
    {{ i + 1 }}. {{ item.name }}
  </li>
} @empty {
  <li>暂无数据</li>
}

内置变量:

变量 说明
$index 当前索引
$first 是否为第一项
$last 是否为最后一项
$even 索引是否为偶数
$odd 索引是否为奇数
$count 总数量

4.3 @switch语法 #

html
@switch (status) {
  @case ('active') {
    <p>激活状态</p>
  }
  @case ('inactive') {
    <p>未激活状态</p>
  }
  @default {
    <p>未知状态</p>
  }
}

五、指令对比 #

5.1 *ngIf vs [hidden] #

html
<!-- *ngIf: 完全移除DOM -->
<div *ngIf="isVisible">内容</div>

<!-- [hidden]: 隐藏DOM,但保留在DOM中 -->
<div [hidden]="!isVisible">内容</div>
方式 特点 适用场景
*ngIf 移除DOM 不频繁切换
[hidden] 隐藏DOM 频繁切换

5.2 ngClass vs class绑定 #

html
<!-- 单个类 -->
<div [class.active]="isActive">内容</div>

<!-- 多个类 -->
<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">内容</div>

5.3 ngStyle vs style绑定 #

html
<!-- 单个样式 -->
<div [style.color]="'red'">内容</div>

<!-- 多个样式 -->
<div [ngStyle]="{'color': 'red', 'font-size': '16px'}">内容</div>

六、实际应用示例 #

6.1 条件渲染列表 #

typescript
@Component({
  template: `
    <div class="user-list">
      <div *ngIf="users.length > 0; else empty">
        <div *ngFor="let user of users; let i = index"
             [ngClass]="{'even': i % 2 === 0, 'odd': i % 2 === 1}">
          <span [ngStyle]="{'color': user.active ? 'green' : 'gray'}">
            {{ user.name }}
          </span>
          <span *ngIf="user.isAdmin" class="badge">管理员</span>
        </div>
      </div>
      
      <ng-template #empty>
        <p class="empty-message">暂无用户数据</p>
      </ng-template>
    </div>
  `
})
export class UserListComponent {
  users: User[] = [];
}

6.2 状态显示 #

typescript
@Component({
  template: `
    <div [ngSwitch]="order.status" class="status-badge">
      <span *ngSwitchCase="'pending'" class="badge-warning">待处理</span>
      <span *ngSwitchCase="'processing'" class="badge-info">处理中</span>
      <span *ngSwitchCase="'shipped'" class="badge-primary">已发货</span>
      <span *ngSwitchCase="'delivered'" class="badge-success">已送达</span>
      <span *ngSwitchCase="'cancelled'" class="badge-danger">已取消</span>
      <span *ngSwitchDefault class="badge-secondary">未知状态</span>
    </div>
  `
})
export class OrderStatusComponent {
  @Input() order: Order;
}

6.3 表格渲染 #

typescript
@Component({
  template: `
    <table class="table">
      <thead>
        <tr>
          <th>#</th>
          <th>名称</th>
          <th>价格</th>
          <th>状态</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let product of products; let i = index"
            [ngClass]="{
              'row-even': i % 2 === 0,
              'row-odd': i % 2 === 1,
              'row-highlight': product.featured
            }">
          <td>{{ i + 1 }}</td>
          <td>{{ product.name }}</td>
          <td [ngStyle]="{'color': product.discount ? 'red' : 'inherit'}">
            {{ product.price | currency }}
          </td>
          <td>
            <span [ngSwitch]="product.status">
              <span *ngSwitchCase="'in_stock'">有货</span>
              <span *ngSwitchCase="'out_of_stock'">缺货</span>
              <span *ngSwitchDefault>未知</span>
            </span>
          </td>
        </tr>
      </tbody>
    </table>
  `
})
export class ProductTableComponent {
  products: Product[] = [];
}

七、性能优化建议 #

7.1 使用trackBy #

typescript
@Component({
  template: `
    <li *ngFor="let item of items; trackBy: trackById">
      {{ item.name }}
    </li>
  `
})
export class ExampleComponent {
  trackById(index: number, item: Item): number {
    return item.id;
  }
}

7.2 避免频繁DOM操作 #

html
<!-- 推荐:使用hidden -->
<div [hidden]="!isVisible">内容</div>

<!-- 不推荐:频繁使用ngIf -->
<div *ngIf="isVisible">内容</div>

7.3 使用OnPush策略 #

typescript
@Component({
  selector: 'app-list',
  template: `...`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListComponent {
  @Input() items: Item[];
}

八、总结 #

指令 类型 用途
*ngIf 结构 条件渲染
*ngFor 结构 列表渲染
*ngSwitch 结构 多条件分支
ngClass 属性 动态类名
ngStyle 属性 动态样式

下一步:自定义指令

最后更新:2026-03-26