填写这份《一分钟调查》,帮我们(开发组)做得更好!去填写Home

内置指令

Built-in directives

指令是为 Angular 应用程序中的元素添加额外行为的类。使用 Angular 的内置指令,你可以管理表单、列表、样式以及要让用户看到的任何内容。

Directives are classes that add additional behavior to elements in your Angular applications. With Angular's built-in directives, you can manage forms, lists, styles, and what users see.

要查看包含本指南中代码的可工作范例,请参阅现场演练 / 下载范例

See the现场演练 / 下载范例for a working example containing the code snippets in this guide.

Angular 指令的不同类型如下:

The different types of Angular directives are as follows:

  1. 组件 —— 带有模板的指令。这种指令类型是最常见的指令类型。

    Components—directives with a template. This type of directive is the most common directive type.

  2. 属性型指令 —— 更改元素、组件或其他指令的外观或行为的指令。

    Attribute directives—directives that change the appearance or behavior of an element, component, or another directive.

  3. 结构型指令 —— 通过添加和删除 DOM 元素来更改 DOM 布局的指令。

    Structural directives—directives that change the DOM layout by adding and removing DOM elements.

本指南涵盖了内置的属性型指令结构型指令

This guide covers built-in attribute directives and structural directives.

内置属性型指令

Built-in attribute directives

属性型指令会监听并修改其它 HTML 元素和组件的行为、Attribute 和 Property。

Attribute directives listen to and modify the behavior of other HTML elements, attributes, properties, and components.

许多 NgModule(例如 RouterModuleFormsModule都定义了自己的属性型指令。最常见的属性型指令如下:

Many NgModules such as the RouterModuleand the FormsModuledefine their own attribute directives. The most common attribute directives are as follows:

  • NgClass—— 添加和删除一组 CSS 类。

    NgClass—adds and removes a set of CSS classes.

  • NgStyle—— 添加和删除一组 HTML 样式。

    NgStyle—adds and removes a set of HTML styles.

  • NgModel—— 将数据双向绑定添加到 HTML 表单元素。

    NgModel—adds two-way data binding to an HTML form element.

NgClass 添加和删除类

Adding and removing classes with NgClass

ngClass 同时添加或删除多个 CSS 类。

You can add or remove multiple CSS classes simultaneously with ngClass.

要添加或删除单个类,请使用类绑定而不是 NgClass

To add or remove a single class, use class binding rather than NgClass.

NgClass 与表达式一起使用

Using NgClass with an expression

在要设置样式的元素上,添加 [ngClass] 并将其设置为等于某个表达式。在这里,是在 app.component.ts 中将 isSpecial 设置为布尔值 true。因为 isSpecial 为 true,所以 ngClass 就会把 special 类应用于此 <div> 上。

On the element you'd like to style, add [ngClass] and set it equal to an expression. In this case, isSpecial is a boolean set to true in app.component.ts. Because isSpecial is true, ngClass applies the class of special to the <div>.

src/app/app.component.html
      
      <!-- toggle the "special" class on/off with a property -->
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
    

NgClass 与方法一起使用

Using NgClass with a method

  1. 要将 NgClass 与方法一起使用,请将方法添加到组件类中。在下面的示例中,setCurrentClasses() 使用一个对象来设置属性 currentClasses,该对象根据另外三个组件属性为 truefalse 来添加或删除三个 CSS 类。

    To use NgClass with a method, add the method to the component class. In the following example, setCurrentClasses() sets the property currentClasses with an object that adds or removes three classes based on the true or false state of three other component properties.

    该对象的每个键(key)都是一个 CSS 类名。如果键为 true,则 ngClass 添加该类。如果键为 false,则 ngClass 删除该类。

    Each key of the object is a CSS class name. If a key is true, ngClass adds the class. If a key is false, ngClass removes the class.

src/app/app.component.ts
      
      currentClasses: Record<string, boolean> = {};
/* . . . */
  setCurrentClasses() {
    // CSS classes: added/removed per current state of component properties
    this.currentClasses =  {
      saveable: this.canSave,
      modified: !this.isUnchanged,
      special:  this.isSpecial
    };
  }
    
  1. 在模板中,把 ngClass 属性绑定到 currentClasses,根据它来设置此元素的 CSS 类:

    In the template, add the ngClass property binding to currentClasses to set the element's classes:

src/app/app.component.html
      
      <div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
    

在这个例子中,Angular 会在初始化以及发生更改的情况下应用这些类。完整的示例会在 ngOnInit() 中进行初始化以及通过单击按钮更改相关属性时调用 setCurrentClasses()。这些步骤对于实现 ngClass 不是必需的。有关更多信息,请参见现场演练 / 下载范例中的 app.component.tsapp.component.html

For this use case, Angular applies the classes on initialization and in case of changes. The full example calls setCurrentClasses() initially with ngOnInit() and when the dependent properties change through a button click. These steps are not necessary to implement ngClass. For more information, see the现场演练 / 下载范例 app.component.ts and app.component.html.

NgStyle 设置内联样式

Setting inline styles with NgStyle

你可以使用 NgStyle 根据组件的状态同时设置多个内联样式。

You can use NgStyle to set multiple inline styles simultaneously, based on the state of the component.

  1. 要使用 NgStyle,请向组件类添加一个方法。

    To use NgStyle, add a method to the component class.

    在下面的例子中,setCurrentStyles() 方法基于该组件另外三个属性的状态,用一个定义了三个样式的对象设置了 currentStyles 属性。

    In the following example, setCurrentStyles() sets the property currentStyles with an object that defines three styles, based on the state of three other component properties.

src/app/app.component.ts
      
      currentStyles: Record<string, string> = {};
/* . . . */
  setCurrentStyles() {
    // CSS styles: set per current state of component properties
    this.currentStyles = {
      'font-style':  this.canSave      ? 'italic' : 'normal',
      'font-weight': !this.isUnchanged ? 'bold'   : 'normal',
      'font-size':   this.isSpecial    ? '24px'   : '12px'
    };
  }
    
  1. 要设置元素的样式,请将 ngStyle 属性绑定到 currentStyles

    To set the element's styles, add an ngStyle property binding to currentStyles.

src/app/app.component.html
      
      <div [ngStyle]="currentStyles">
  This div is initially italic, normal weight, and extra large (24px).
</div>
    

在这个例子中,Angular 会在初始化以及发生更改的情况下应用这些类。完整的示例会在 ngOnInit() 中进行初始化以及通过单击按钮更改相关属性时调用 setCurrentClasses()。这些步骤对于实现 ngClass 不是必需的。有关更多信息,请参见现场演练 / 下载范例中的 app.component.tsapp.component.html

For this use case, Angular applies the styles upon initialization and in case of changes. To do this, the full example calls setCurrentStyles() initially with ngOnInit() and when the dependent properties change through a button click. However, these steps are not necessary to implement ngStyle on its own. See the现场演练 / 下载范例 app.component.ts and app.component.html for this optional implementation.

ngModel 显示和更新属性

Displaying and updating properties with ngModel

你可以使用 NgModel 指令显示数据属性,并在用户进行更改时更新该属性。

You can use the NgModel directive to display a data property and update that property when the user makes changes.

  1. 导入 FormsModule,并将其添加到 NgModule 的 imports 列表中。

    Import FormsModule and add it to the NgModule's imports list.

src/app/app.module.ts (FormsModule import)
      
      import { FormsModule } from '@angular/forms'; // <--- JavaScript import from Angular
/* . . . */
@NgModule({
/* . . . */

  imports: [
    BrowserModule,
    FormsModule // <--- import into the NgModule
  ],
/* . . . */
})
export class AppModule { }
    
  1. 在 HTML 的 <form> 元素上添加 [(ngModel)] 绑定,并将其设置为等于此属性,这里是 name

    Add an [(ngModel)] binding on an HTML <form> element and set it equal to the property, here name.

src/app/app.component.html (NgModel example)
      
      <label for="example-ngModel">[(ngModel)]:</label>
<input [(ngModel)]="currentItem.name" id="example-ngModel">
    

[(ngModel)] 语法只能设置数据绑定属性。

This [(ngModel)] syntax can only set a data-bound property.

要自定义配置,你可以编写可展开的表单,该表单将属性绑定和事件绑定分开。使用属性绑定来设置属性,并使用事件绑定来响应更改。以下示例将 <input> 值更改为大写:

To customize your configuration, you can write the expanded form, which separates the property and event binding. Use property binding to set the property and event binding to respond to changes. The following example changes the <input> value to uppercase:

src/app/app.component.html
      
      <input [ngModel]="currentItem.name" (ngModelChange)="setUppercaseName($event)" id="example-uppercase">
    

这里是所有这些变体的动画,包括这个大写转换的版本:

Here are all variations in action, including the uppercase version:

NgModel 和值访问器

NgModel and value accessors

NgModel 指令适用于ControlValueAccessor支持的元素。Angular 为所有基本 HTML 表单元素提供了值访问器。有关更多信息,请参见Forms

The NgModel directive works for an element supported by a ControlValueAccessor. Angular provides value accessors for all of the basic HTML form elements. For more information, see Forms.

要将 [(ngModel)] 应用于非格式本机元素或第三方自定义组件,必须编写一个值访问器。有关更多信息,请参见DefaultValueAccessor上的 API 文档。

To apply [(ngModel)] to a non-form native element or a third-party custom component, you have to write a value accessor. For more information, see the API documentation on DefaultValueAccessor.

编写 Angular 组件时,如果根据 Angular 的双向绑定语法命名 value 和 event 属性,则不需要用值访问器(ControlValueAccessor)或 NgModel

When you write an Angular component, you don't need a value accessor or NgModel if you name the value and event properties according to Angular's two-way binding syntax.

内置结构型指令

Built-in structural directives

结构型指令的职责是 HTML 布局。 它们塑造或重塑 DOM 的结构,这通常是通过添加、移除和操纵它们所附加到的宿主元素来实现的。

Structural directives are responsible for HTML layout. They shape or reshape the DOM's structure, typically by adding, removing, and manipulating the host elements to which they are attached.

本节会介绍最常见的内置结构型指令:

This section introduces the most common built-in structural directives:

  • NgIf—— 从模板中创建或销毁子视图。

    NgIf—conditionally creates or disposes of subviews from the template.

  • NgFor—— 为列表中的每个条目重复渲染一个节点。

    NgFor—repeat a node for each item in a list.

  • NgSwitch—— 一组在备用视图之间切换的指令。

    NgSwitch—a set of directives that switch among alternative views.

要了解更多信息,参阅结构型指令

For more information, see Structural Directives.

NgIf 添加或删除元素

Adding or removing an element with NgIf

你可以通过将 NgIf 指令应用于宿主元素来添加或删除元素。

You can add or remove an element by applying an NgIf directive to a host element.

如果 NgIffalse,则 Angular 将从 DOM 中移除一个元素及其后代。然后,Angular 会销毁其组件,从而释放内存和资源。

When NgIf is false, Angular removes an element and its descendants from the DOM. Angular then disposes of their components, which frees up memory and resources.

要添加或删除元素,请在以下示例 *ngIf 绑定到条件表达式,例如 isActive

To add or remove an element, bind *ngIf to a condition expression such as isActive in the following example.

src/app/app.component.html
      
      <app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
    

isActive 表达式返回真值时,NgIf 会把 ItemDetailComponent 添加到 DOM 中。当表达式为假值时,NgIf 会从 DOM 中删除 ItemDetailComponent 并销毁该组件及其所有子组件。

When the isActive expression returns a truthy value, NgIf adds the ItemDetailComponent to the DOM. When the expression is falsy, NgIf removes the ItemDetailComponent from the DOM and disposes of the component and all of its sub-components.

关于 NgIfNgIfElse 的更多信息,请参见NgIf API 文档

For more information on NgIf and NgIfElse, see the NgIf API documentation.

防止 null

Guarding against null

默认情况下,NgIf 会阻止显示已绑定到空值的元素。

By default, NgIf prevents display of an element bound to a null value.

要使用 NgIf 保护 <div>,请将 *ngIf="yourProperty" 添加到此 <div>。在下面的例子中,currentCustomer 名字出现了,是因为确实存在一个 currentCustomer

To use NgIf to guard a <div>, add *ngIf="yourProperty" to the <div>. In the following example, the currentCustomer name appears because there is a currentCustomer.

src/app/app.component.html
      
      <div *ngIf="currentCustomer">Hello, {{currentCustomer.name}}</div>
    

但是,如果该属性为 null,则 Angular 就不会显示 <div>。在这个例子中,Angular 就不会显示 nullCustomer,因为它为 null

However, if the property is null, Angular does not display the <div>. In this example, Angular does not display the nullCustomer because it is null.

src/app/app.component.html
      
      <div *ngIf="nullCustomer">Hello, <span>{{nullCustomer}}</span></div>
    

NgFor 条目列表

Listing items with NgFor

你可以使用 NgFor 来指令显示条目列表。

You can use the NgFor directive to present a list of items.

  1. 定义一个 HTML 块,该块会决定 Angular 如何渲染单个条目。

    Define a block of HTML that determines how Angular renders a single item.

  2. 要列出你的条目,请把一个简写形式 let item of items 赋值给 *ngFor

    To list your items, assign the short hand let item of items to *ngFor.

src/app/app.component.html
      
      <div *ngFor="let item of items">{{item.name}}</div>
    

字符串 "let item of items" 会指示 Angular 执行以下操作:

The string "let item of items" instructs Angular to do the following:

  • items 中的每个条目存储在局部循环变量 item

    Store each item in the items array in the local item looping variable

  • 让每个条目都可用于每次迭代时的模板 HTML 中

    Make each item available to the templated HTML for each iteration

  • "let item of items" 转换为环绕宿主元素的 <ng-template>

    Translate "let item of items" into an <ng-template> around the host element

  • 对列表中的每个 item 复写这个 <ng-template>

    Repeat the <ng-template> for each item in the list

欲知详情,请参阅结构型指令中的结构型指令的简写形式部分。

For more information see the Structural directive shorthand section of Structural directives.

复写组件视图

Repeating a component view

要复写某个组件元素,请将 *ngFor 应用于其选择器。在以下示例中,选择器为 <app-item-detail>

To repeat a component element, apply *ngFor to the selector. In the following example, the selector is <app-item-detail>.

src/app/app.component.html
      
      <app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
    

你可以在以下位置引用模板输入变量,例如 item

You can reference a template input variable, such as item, in the following locations:

  • ngFor 的宿主元素中

    within the ngFor host element

  • 在宿主元素的后代中,用以访问条目的属性

    within the host element descendants to access the item's properties

以下示例首先在插值中引用 item,然后将它通过绑定传递给 <app-item-detail> 组件的 item 属性。

The following example references item first in an interpolation and then passes in a binding to the item property of the <app-item-detail> component.

src/app/app.component.html
      
      <div *ngFor="let item of items">{{item.name}}</div>
<!-- . . . -->
  <app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
    

有关模板输入变量的更多信息,请参见《结构型指令简写形式》](guide/structural-directives#shorthand)。

For more information about template input variables, see Structural directive shorthand.

获取 *ngForindex

Getting the index of *ngFor

你可以获取 *ngForindex,并在模板中使用它。

You can get the index of *ngFor in a template input variable and use it in the template.

*ngFor 中,添加一个分号和 let i=index 简写形式。下面的例子中把 index 取到一个名为 i 的变量中,并将其与条目名称一起显示。

In the *ngFor, add a semicolon and let i=index to the short hand. The following example gets the index in a variable named i and displays it with the item name.

src/app/app.component.html
      
      <div *ngFor="let item of items; let i=index">{{i + 1}} - {{item.name}}</div>
    

NgFor 指令上下文的 index 属性在每次迭代中都会返回该条目的从零开始的索引号。

The index property of the NgFor directive context returns the zero-based index of the item in each iteration.

Angular 会将此指令转换为 <ng-template>,然后反复使用此模板为列表中的每个 item 创建一组新的元素和绑定。有关简写形式的更多信息,请参见《结构型指令》指南。

Angular translates this instruction into an <ng-template> around the host element, then uses this template repeatedly to create a new set of elements and bindings for each item in the list. For more information about shorthand, see the Structural Directives guide.

当条件为真时复写元素

Repeating elements when a condition is true

要在特定条件为 true 时复写 HTML 块,请将 *ngIf 放在 *ngFor 元素的容器元素上。它们之一或两者都可以是 <ng-container>,这样你就不必引入额外的 HTML 层次了。

To repeat a block of HTML when a particular condition is true, put the *ngIf on a container element that wraps an *ngFor element. One or both elements can be an <ng-container> so you don't have to introduce extra levels of HTML.

由于结构型指令会在 DOM 中添加和删除节点,因此每个元素只能应用一个结构型指令。

Because structural directives add and remove nodes from the DOM, apply only one structural directive per element.

有关 NgFor 的更多信息,请参见NgForOf API 参考

For more information about NgFor see the NgForOf API reference.

*ngFortrackBy 跟踪条目

Tracking items with *ngFor trackBy

通过跟踪对条目列表的更改,可以减少应用程序对服务器的调用次数。使用 *ngFortrackBy 属性,Angular 只能更改和重新渲染已更改的条目,而不必重新加载整个条目列表。

By tracking changes to an item list, you can reduce the number of calls your application makes to the server. With the *ngFor trackBy property, Angular can change and re-render only those items that have changed, rather than reloading the entire list of items.

  1. 向该组件添加一个方法,该方法返回 NgFor 应该跟踪的值。这个例子中,该值是英雄的 id。如果浏览器已经渲染过此 id,Angular 就会跟踪它,而不会重新向服务器查询相同的 id

    Add a method to the component that returns the value NgFor should track. In this example, the value to track is the item's id. If the browser has already rendered id, Angular keeps track of it and doesn't re-query the server for the same id.

src/app/app.component.ts
      
      trackByItems(index: number, item: Item): number { return item.id; }
    
  1. 在简写表达式中,将 trackBy 设置为 trackByItems() 方法。

    In the short hand expression, set trackBy to the trackByItems() method.

src/app/app.component.html
      
      <div *ngFor="let item of items; trackBy: trackByItems">
  ({{item.id}}) {{item.name}}
</div>
    

更改这些 ID 会使用新的 item.id 创建新的条目。在下面的 trackBy 效果演示中,Reset items 会创建一些具有和以前相同的 item.id 的新条目。

Change ids creates new items with new item.ids. In the following illustration of the trackBy effect, Reset items creates new items with the same item.ids.

  • 如果没有 trackBy,这些按钮都会触发完全的 DOM 元素替换。

    With no trackBy, both buttons trigger complete DOM element replacement.

  • 有了 trackBy,则只有修改了 id 的按钮才会触发元素替换。

    With trackBy, only changing the id triggers element replacement.

内置指令仅仅使用了公共 API。它们没有用到任何其它指令无权访问的私有 API。

Built-in directives use only public APIs. They do not have special access to any private APIs that other directives can't access.

为没有 DOM 元素的指令安排宿主

Hosting a directive without a DOM element

Angular 的 <ng-container> 是一个分组元素,它不会干扰样式或布局,因为 Angular 不会将其放置在 DOM 中。

The Angular <ng-container> is a grouping element that doesn't interfere with styles or layout because Angular doesn't put it in the DOM.

当没有单个元素承载指令时,可以使用 <ng-container>

You can use <ng-container> when there's no single element to host the directive.

这是使用 <ng-container> 的条件化段落。

Here's a conditional paragraph using <ng-container>.

src/app/app.component.html (ngif-ngcontainer)
      
      <p>
  I turned the corner
  <ng-container *ngIf="hero">
    and saw {{hero.name}}. I waved
  </ng-container>
  and continued on my way.
</p>
    
  1. FormsModule 中导入 ngModel 指令。

    Import the ngModel directive from FormsModule.

  2. FormsModule 添加到相关 Angular 模块的 imports 部分。

    Add FormsModule to the imports section of the relevant Angular module.

  3. 要有条件地排除 <option>,请将 <option> 包裹在 <ng-container> 中。

    To conditionally exclude an <option>, wrap the <option> in an <ng-container>.

    src/app/app.component.html (select-ngcontainer)
          
          <div>
      Pick your favorite hero
      (<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
    </div>
    <select [(ngModel)]="hero">
      <ng-container *ngFor="let h of heroes">
        <ng-container *ngIf="showSad || h.emotion !== 'sad'">
          <option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
        </ng-container>
      </ng-container>
    </select>
        

NgSwitch

Switching cases with NgSwitch

就像 JavaScript 的 switch 语句一样。NgSwitch 会根据切换条件显示几个可能的元素中的一个。Angular 只会将选定的元素放入 DOM。

Like the JavaScript switch statement, NgSwitch displays one element from among several possible elements, based on a switch condition. Angular puts only the selected element into the DOM.

NgSwitch 是一组指令(共三个):

NgSwitch is a set of three directives:

  • NgSwitch —— 一个属性型指令,它更改其伴生指令的行为。

    NgSwitch—an attribute directive that changes the behavior of its companion directives.

  • NgSwitchCase —— 结构型指令,当其绑定值等于开关值时将其元素添加到 DOM 中,而在其不等于开关值时将其绑定值移除。

    NgSwitchCase—structural directive that adds its element to the DOM when its bound value equals the switch value and removes its bound value when it doesn't equal the switch value.

  • NgSwitchDefault —— 结构型指令,当没有选中的 NgSwitchCase 时,将其宿主元素添加到 DOM 中。

    NgSwitchDefault—structural directive that adds its element to the DOM when there is no selected NgSwitchCase.

  1. 在每个元素(比如<div>)上,把 [ngSwitch] 绑定到一个返回开关值的表达式(例如 feature)。尽管这个例子中 feature 值是字符串,但此开关值可以是任何类型。

    On an element, such as a <div>, add [ngSwitch] bound to an expression that returns the switch value, such as feature. Though the feature value in this example is a string, the switch value can be of any type.

  2. 将各个分支元素绑定到 *ngSwitchCase*ngSwitchDefault

    Bind to *ngSwitchCase and *ngSwitchDefault on the elements for the cases.

    src/app/app.component.html
          
          <div [ngSwitch]="currentItem.feature">
      <app-stout-item    *ngSwitchCase="'stout'"    [item]="currentItem"></app-stout-item>
      <app-device-item   *ngSwitchCase="'slim'"     [item]="currentItem"></app-device-item>
      <app-lost-item     *ngSwitchCase="'vintage'"  [item]="currentItem"></app-lost-item>
      <app-best-item     *ngSwitchCase="'bright'"   [item]="currentItem"></app-best-item>
    <!-- . . . -->
      <app-unknown-item  *ngSwitchDefault           [item]="currentItem"></app-unknown-item>
    </div>
        
  3. 在父组件中,定义 currentItem 以便可以在 [ngSwitch] 表达式中使用它。

    In the parent component, define currentItem so you can use it in the [ngSwitch] expression.

    src/app/app.component.ts
          
          currentItem!: Item;
        
  4. 在每个子组件中,添加一个输入属性 item,该属性会绑定到父组件的 currentItem。以下两个片段显示了父组件和其中一个子组件。其他子组件与 StoutItemComponent 中的相同。

    In each child component, add an item input property which is bound to the currentItem of the parent component. The following two snippets show the parent component and one of the child components. The other child components are identical to StoutItemComponent.

    In each child component, here StoutItemComponent
          
          export class StoutItemComponent {
      @Input() item!: Item;
    }
        

Switch 指令也同样适用于原生 HTML 元素和 Web Component。 比如,你可以像下面的例子中一样把 <app-best-item> 分支替换为 <div>

Switch directives also work with native HTML elements and web components. For example, you could replace the <app-best-item> switch case with a <div> as follows.

src/app/app.component.html
      
      <div *ngSwitchCase="'bright'"> Are you as bright as {{currentItem.name}}?</div>
    

接下来呢?

What's next

有关如何构建自己的自定义指令的信息,请参见“属性型指令”“结构型指令”

For information on how to build your own custom directives, see Attribute Directives and Structural Directives.