深入指南
範本

範本中的變數

Angular 在範本中有兩種變數宣告:區域範本變數與範本參照變數。

HELPFUL: 在本指南中,「範本」並不是指整個 HTML 範本檔案。它只指檔案中某個特定的範本結構或運算式。

使用 @let 的區域範本變數

Angular 的 @let 語法讓你能定義一個區域變數,並在整個範本中重複使用它,類似 JavaScript let 語法。

使用 @let

使用 @let 宣告一個變數,其值以範本運算式的結果為基礎。Angular 會自動讓變數的值隨著給定的運算式保持最新,類似繫結。

@let name = user.name;
@let greeting = 'Hello, ' + name;
@let data = data$ | async;
@let pi = 3.14159;
@let coordinates = {x: 50, y: 100};
@let longExpression =
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit ' +
  'sed do eiusmod tempor incididunt ut labore et dolore magna ' +
  'Ut enim ad minim veniam...';

每個 @let 區塊只能宣告一個變數。你不能在同一個區塊中用逗號宣告多個變數。

參照 @let 的值

用 @let 宣告變數之後,你可以在同一個範本中重複使用它:

@let user = user$ | async;

@if (user) {
  <h1>Hello, {{ user.name }}</h1>
  <user-avatar [photo]="user.photo" />

  <ul>
    @for (snack of user.favoriteSnacks; track snack.id) {
      <li>{{ snack.name }}</li>
    }
  </ul>

  <button (click)="update(user)">Update profile</button>
}

可指派性

@let 與 JavaScript 的 let 之間的一個關鍵差異是,@let 在宣告之後不能重新指派。不過,Angular 會自動讓變數的值隨著給定的運算式保持最新。

@let value = 1;

<!-- Invalid - This does not work! -->
<button (click)="value = value + 1">Increment the value</button>

變數範圍

@let 宣告的範圍限於目前檢視及其後代。Angular 會在元件邊界,以及範本中可能包含動態內容的任何地方建立新檢視,例如控制流程區塊、@defer 區塊或結構指令。

由於 @let 宣告不會被提升(hoist),它們無法被父檢視或同層檢視存取:

@let topLevel = value;

<div>
  @let insideDiv = value;
</div>

<!-- Valid -->
{{ topLevel }}
<!-- Valid -->
{{ insideDiv }}

@if (condition) {
  <!-- Valid -->
  {{ topLevel + insideDiv }}

  @let nested = value;

  @if (condition) {
    <!-- Valid -->
    {{ topLevel + insideDiv + nested }}
  }
}

<!-- Error, not hoisted from @if -->
{{ nested }}

完整語法

@let 語法的正式定義如下:

  • @let 關鍵字。
  • 接著一個或多個空白字元,不包括換行。
  • 接著一個有效的 JavaScript 名稱與零個或多個空白字元。
  • 接著 = 符號與零個或多個空白字元。
  • 接著一個 Angular 運算式,可以跨多行。
  • 以 ; 符號結尾。

範本參照變數

範本參照變數讓你能宣告一個變數,用來參照範本中某個元素的值。

範本參照變數可以參照以下項目:

你可以使用範本參照變數,在同一個範本中,從某個部分讀取資訊並用於另一個部分。

宣告範本參照變數

你可以在範本中的元素上加入一個以井字字元(#)開頭、後接變數名稱的屬性,來宣告變數。

<!-- Create a template reference variable named "taskInput", referring to the HTMLInputElement. -->
<input #taskInput placeholder="Enter task name" />

將值指派給範本參照變數

Angular 會根據變數宣告所在的元素,將值指派給範本變數。

如果你在 Angular 元件上宣告變數,該變數會參照該元件執行個體。

<!-- The `startDate` variable is assigned the instance of `MyDatepicker`. -->
<my-datepicker #startDate />

如果你在 <ng-template> 元素上宣告變數,該變數會參照代表該範本的 TemplateRef 執行個體。詳情請參閱結構指令中的Angular 如何使用星號 * 語法。

<!-- The `myFragment` variable is assigned the `TemplateRef` instance corresponding to this template fragment. -->
<ng-template #myFragment>
  <p>This is a template fragment</p>
</ng-template>

如果你在任何其他顯示元素上宣告變數,該變數會參照 HTMLElement 執行個體。

<!-- The "taskInput" variable refers to the HTMLInputElement instance. -->
<input #taskInput placeholder="Enter task name" />

將參照指派給 Angular 指令

Angular 指令可能有一個 exportAs 屬性,定義該指令在範本中可被參照的名稱:

@Directive({
  selector: '[dropZone]',
  exportAs: 'dropZone',
})
export class DropZone {
  /* ... */
}

當你在元素上宣告範本變數時,可以指定這個 exportAs 名稱,將該變數指派為指令執行個體:

<!-- The `firstZone` variable refers to the `DropZone` directive instance. -->
<section dropZone #firstZone="dropZone">...</section>

你不能參照沒有指定 exportAs 名稱的指令。

搭配查詢使用範本參照變數

除了使用範本變數從同一個範本的其他部分讀取值之外,你也可以使用這種變數宣告方式,「標記」某個元素,以供元件與指令查詢使用。

當你想查詢範本中的特定元素時,你可以在該元素上宣告範本變數,然後根據變數名稱查詢該元素。

<input #description value="Original description" />
@Component({
  /* ... */,
  template: `<input #description value="Original description">`,
})
export class AppComponent {
  // Query for the input element based on the template variable name.
  @ViewChild('description') input: ElementRef | undefined;
}

若要了解查詢的更多資訊,請參閱使用查詢參照子項。

範本變數範圍

就像 JavaScript 或 TypeScript 程式碼中的變數一樣,範本變數的範圍限於宣告它們的範本。

同樣地,像 @if 與 @for 這類控制流程區塊、結構指令與 <ng-template> 宣告都會建立一個新的巢狀範本範圍,很像 JavaScript 的 if 與 for 這類控制流程敘述會建立新的語彙範圍。你不能從這些巢狀範本的邊界之外,存取其中的範本變數。

HELPFUL: 在範本中只定義變數一次,讓執行階段的值保持可預測。

在巢狀範本中存取

內層範本可以存取外層範本定義的範本變數。

在以下範例中,變更 <input> 中的文字會變更 <span> 中的值,因為 Angular 會透過範本變數 ref1 立即更新變更。

<input #ref1 type="text" [(ngModel)]="firstExample" />

@if (true) {
  <span>Value: {{ ref1.value }}</span>
}

在這個情況下,@if 區塊會建立一個新的範本範圍,其中包含來自父範圍的 ref1 變數。

不過,從父範本存取子範圍中的範本變數並不可行:

Avoid
@if (true) {
  <input #ref2 type="text" [(ngModel)]="secondExample" />
}

<span>Value: {{ ref2?.value }}</span>

在這裡,ref2 是在 @if 建立的子範圍中宣告的,無法從父範本存取。