# Template syntax # 模板语法 The Angular application manages what the user sees and can do, achieving this through the interaction of a component class instance (the *component*) and its user-facing template. Angular 应用管理着用户之所见和所为,并通过 Component 类的实例(*组件*)和面向用户的模板交互来实现这一点。 You may be familiar with the component/template duality from your experience with model-view-controller (MVC) or model-view-viewmodel (MVVM). In Angular, the component plays the part of the controller/viewmodel, and the template represents the view. 从使用模型-视图-控制器 (MVC) 或模型-视图-视图模型 (MVVM) 的经验中,很多开发人员都熟悉了组件和模板这两个概念。 在 Angular 中,组件扮演着控制器或视图模型的角色,模板则扮演视图的角色。 This page is a comprehensive technical reference to the Angular template language. It explains basic principles of the template language and describes most of the syntax that you'll encounter elsewhere in the documentation. 这是一篇关于 Angular 模板语言的技术大全。 它解释了模板语言的基本原理,并描述了你将在文档中其它地方遇到的大部分语法。 Many code snippets illustrate the points and concepts, all of them available in the . 这里还有很多代码片段用来解释技术点和概念,它们全都在中。 {@a html} ## HTML in templates ## 模板中的 HTML HTML is the language of the Angular template. Almost all HTML syntax is valid template syntax. The ` Syntax" is the interpolated evil title. "Template alert("evil never sleeps")Syntax" is the property bound evil title.
{@a other-bindings} ## Attribute, class, and style bindings ## attribute、class 和 style 绑定 The template syntax provides specialized one-way bindings for scenarios less well-suited to property binding. 模板语法为那些不太适合使用属性绑定的场景提供了专门的单向数据绑定形式。 To see attribute, class, and style bindings in a functioning app, see the especially for this section. 要在运行中的应用查看 Attribute 绑定、类绑定和样式绑定,请参见 特别是对于本节。 ### Attribute binding ### attribute 绑定 Set the value of an attribute directly with an **attribute binding**. This is the only exception to the rule that a binding sets a target property and the only binding that creates and sets an attribute. 可以直接使用 **Attribute 绑定**设置 Attribute 的值。一般来说,绑定时设置的是目标的 Property,而 Attribute 绑定是唯一的例外,它创建和设置的是 Attribute。 Usually, setting an element property with a [property binding](guide/template-syntax#property-binding) is preferable to setting the attribute with a string. However, sometimes there is no element property to bind, so attribute binding is the solution. 通常,使用 [Property 绑定](guide/template-syntax#property-binding)设置元素的 Property 优于使用字符串设置 Attribute。但是,有时没有要绑定的元素的 Property,所以其解决方案就是 Attribute 绑定。 Consider the [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) and [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG). They are purely attributes, don't correspond to element properties, and don't set element properties. In these cases, there are no property targets to bind to. 考虑 [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) 和 [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG) 。它们都纯粹是 Attribute,不对应于元素的 Property,也不能设置元素的 Property。 在这些情况下,就没有要绑定到的目标 Property。 Attribute binding syntax resembles property binding, but instead of an element property between brackets, start with the prefix `attr`, followed by a dot (`.`), and the name of the attribute. You then set the attribute value, using an expression that resolves to a string, or remove the attribute when the expression resolves to `null`. Attribute 绑定的语法类似于 Property 绑定,但其括号之间不是元素的 Property,而是由前缀 `attr`、点( `.` )和 Attribute 名称组成。然后,您就可以使用能解析为字符串的表达式来设置该 Attribute 的值,或者当表达式解析为 `null` 时删除该 Attribute。 One of the primary use cases for attribute binding is to set ARIA attributes, as in this example: attribute 绑定的主要用例之一是设置 ARIA attribute(译注:ARIA 指无障碍功能,用于给残障人士访问互联网提供便利), 就像这个例子中一样:
#### `colspan` and `colSpan` #### `colspan` 和 `colSpan` Notice the difference between the `colspan` attribute and the `colSpan` property. 注意 `colspan` Attribute 和 `colSpan` Property 之间的区别。 If you wrote something like this: 如果您这样写: <tr><td colspan="{{1 + 1}}">Three-Four</td></tr> You'd get this error: 您会收到如下错误: Template parse errors: Can't bind to 'colspan' since it isn't a known native property As the message says, the `` element does not have a `colspan` property. This is true because `colspan` is an attribute—`colSpan`, with a capital `S`, is the corresponding property. Interpolation and property binding can set only *properties*, not attributes. 如错误消息所示,`` 元素没有 `colspan` 这个 Property。这是正确的,因为 `colspan` 是一个 Attribute,而 `colSpan` (`colSpan` 中的 `S` 是大写)则是相应的 Property。插值和 Property 绑定只能设置 *Property* ,不能设置 Attribute。 Instead, you'd use property binding and write it like this: 相反,您可以使用 Property 绑定并将其改写为:

### Class binding ### 类绑定 Add and remove CSS class names from an element's `class` attribute with a **class binding**. 使用**类绑定**可以从元素的 `class` 属性中添加和删除 CSS 类名称。 Here's how to set the attribute without binding in plain HTML: 下面是在普通 HTML 中不用绑定来设置 Attribute 的方法: ```html
Item clearance special
``` Class binding syntax resembles property binding, but instead of an element property between brackets, start with the prefix `class`, optionally followed by a dot (`.`) and the name of a CSS class: `[class.class-name]`. 类绑定语法类似于 Property 绑定,但其括号之间不是元素的 Property,而是由前缀 `class`、点(`.`)和 CSS 类名(点和 CSS 类名可选)组成 `[class.class-name]` : `[class.class-name]` 。 You can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding. 可以把它改写为绑定到所需 CSS 类名的绑定;这是一个或者全有或者全无的替换型绑定。 (译注:即当 resetClasses 有值时 class 这个 attribute 设置的内容会被完全覆盖) You can also add a class to an element without overwriting the classes already on the element: 您还可以将一个类添加到元素上,而不会覆盖该元素上已经存在的类: Finally, you can bind to a specific class name. Angular adds the class when the template expression evaluates to truthy. It removes the class when the expression is falsy. 最后,可以绑定到特定的类名。 当模板表达式的求值结果是真值时,Angular 会添加这个类,反之则移除它。 While this technique is suitable for toggling a single class name, consider the [`NgClass`](guide/template-syntax#ngClass) directive when managing multiple class names at the same time. 尽管此技术适用于切换单个类名,但在需要同时管理多个类名时请考虑使用 [`NgClass`](guide/template-syntax#ngClass) 指令。
### Style binding ### 样式绑定 You can set inline styles with a **style binding**. 通过**样式绑定**,可以设置内联样式。 Style binding syntax resembles property binding. Instead of an element property between brackets, start with the prefix `style`, followed by a dot (`.`) and the name of a CSS style property: `[style.style-property]`. 样式绑定的语法与属性绑定类似。 但方括号中的部分不是元素的属性名,而由**`style`**前缀,一个点 (`.`)和 CSS 样式的属性名组成。 形如:`[style.style-property]`。 Some style binding styles have a unit extension. The following example conditionally sets the font size in “em” and “%” units. 有些样式绑定中的样式带有单位。在这里,以根据条件用 “em” 和 “%” 来设置字体大小的单位。 This technique is suitable for setting a single style, but consider the [`NgStyle`](guide/template-syntax#ngStyle) directive when setting several inline styles at the same time. 此技术适用于设置单个样式,当需要同时设置多个内联样式时请考虑使用 [`NgStyle`](guide/template-syntax#ngStyle) 指令。
Note that a _style property_ name can be written in either [dash-case](guide/glossary#dash-case), as shown above, or [camelCase](guide/glossary#camelcase), such as `fontSize`. 注意,*样式属性*命名方法可以用[中线命名法](guide/glossary#dash-case),像上面的一样 也可以用[驼峰式命名法](guide/glossary#camelcase),如 `fontSize`。

{@a event-binding} ## Event binding `(event)` ## 事件绑定 `(event)` Event binding allows you to listen for certain events such as keystrokes, mouse movements, clicks, and touches. For an example demonstrating all of the points in this section, see the event binding example. 事件绑定允许你监听某些事件,比如按键、鼠标移动、点击和触屏。要查看本节中所有要点的演示,请参见事件绑定范例。 Angular event binding syntax consists of a **target event** name within parentheses on the left of an equal sign, and a quoted template statement on the right. The following event binding listens for the button's click events, calling the component's `onSave()` method whenever a click occurs: Angular 的事件绑定语法由等号左侧带圆括号的**目标事件**和右侧引号中的[模板语句](guide/template-syntax#template-statements)组成。 下面事件绑定监听按钮的点击事件。每当点击发生时,都会调用组件的 `onSave()` 方法。 ### Target event ### 目标事件 As above, the target is the button's click event. 如前所述,其目标就是此按钮的单击事件。 Alternatively, use the `on-` prefix, known as the canonical form: 有些人更喜欢带 `on-` 前缀的备选形式,称之为**规范形式**: Element events may be the more common targets, but Angular looks first to see if the name matches an event property of a known directive, as it does in the following example: 元素事件可能是更常见的目标,但 Angular 会先看这个名字是否能匹配上已知指令的事件属性,就像下面这个例子: If the name fails to match an element event or an output property of a known directive, Angular reports an “unknown directive” error. 如果这个名字没能匹配到元素事件或已知指令的输出属性,Angular 就会报“未知指令”错误。 ### *$event* and event handling statements ### *$event* 和事件处理语句 In an event binding, Angular sets up an event handler for the target event. 在事件绑定中,Angular 会为目标事件设置事件处理器。 When the event is raised, the handler executes the template statement. The template statement typically involves a receiver, which performs an action in response to the event, such as storing a value from the HTML control into a model. 当事件发生时,这个处理器会执行模板语句。 典型的模板语句通常涉及到响应事件执行动作的接收器,例如从 HTML 控件中取得值,并存入模型。 The binding conveys information about the event. This information can include data values such as an event object, string, or number named `$event`. 绑定会通过**名叫 `$event` 的事件对象**传递关于此事件的信息(包括数据值)。 The target event determines the shape of the `$event` object. If the target event is a native DOM element event, then `$event` is a [DOM event object](https://developer.mozilla.org/en-US/docs/Web/Events), with properties such as `target` and `target.value`. 事件对象的形态取决于目标事件。如果目标事件是原生 DOM 元素事件, `$event` 就是 [DOM 事件对象](https://developer.mozilla.org/en-US/docs/Web/Events),它有像 `target` 和 `target.value` 这样的属性。 Consider this example: 考虑这个范例: This code sets the `` `value` property by binding to the `name` property. To listen for changes to the value, the code binds to the `input` event of the `` element. When the user makes changes, the `input` event is raised, and the binding executes the statement within a context that includes the DOM event object, `$event`. 上面的代码在把输入框的 `value` 属性绑定到 `name` 属性。 要监听对值的修改,代码绑定到输入框的 `input` 事件。 当用户造成更改时,`input` 事件被触发,并在包含了 DOM 事件对象 (`$event`) 的上下文中执行这条语句。 To update the `name` property, the changed text is retrieved by following the path `$event.target.value`. 要更新 `name` 属性,就要通过路径 `$event.target.value` 来获取更改后的值。 If the event belongs to a directive—recall that components are directives—`$event` has whatever shape the directive produces. 如果事件属于指令(回想一下,组件是指令的一种),那么 `$event` 具体是什么由指令决定。 ### Custom events with `EventEmitter` ### 使用 `EventEmitter` 实现自定义事件 Directives typically raise custom events with an Angular [EventEmitter](api/core/EventEmitter). The directive creates an `EventEmitter` and exposes it as a property. The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload, which can be anything. Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object. 通常,指令使用 Angular [EventEmitter](api/core/EventEmitter) 来触发自定义事件。 指令创建一个 `EventEmitter` 实例,并且把它作为属性暴露出来。 指令调用 `EventEmitter.emit(payload)` 来触发事件,可以传入任何东西作为消息载荷。 父指令通过绑定到这个属性来监听事件,并通过 `$event` 对象来访问载荷。 Consider an `ItemDetailComponent` that presents item information and responds to user actions. Although the `ItemDetailComponent` has a delete button, it doesn't know how to delete the hero. It can only raise an event reporting the user's delete request. 假设 `HeroDetailComponent` 用于显示英雄的信息,并响应用户的动作。 虽然 `HeroDetailComponent` 包含删除按钮,但它自己并不知道该如何删除这个英雄。 最好的做法是触发事件来报告“删除用户”的请求。 Here are the pertinent excerpts from that `ItemDetailComponent`: 下面的代码节选自 `HeroDetailComponent`: The component defines a `deleteRequest` property that returns an `EventEmitter`. When the user clicks *delete*, the component invokes the `delete()` method, telling the `EventEmitter` to emit an `Item` object. 组件定义了 `deleteRequest` 属性,它是 `EventEmitter` 实例。 当用户点击*删除*时,组件会调用 `delete()` 方法,让 `EventEmitter` 发出一个 `Hero` 对象。 Now imagine a hosting parent component that binds to the `deleteRequest` event of the `ItemDetailComponent`. 现在,假设有个宿主的父组件,它绑定了 `HeroDetailComponent` 的 `deleteRequest` 事件。 When the `deleteRequest` event fires, Angular calls the parent component's `deleteItem()` method, passing the *item-to-delete* (emitted by `ItemDetail`) in the `$event` variable. 当 `deleteRequest` 事件触发时,Angular 调用父组件的 `deleteHero` 方法, 在 `$event` 变量中传入*要删除的英雄*(来自 `HeroDetail`)。 ### Template statements have side effects ### 模板语句有副作用 Though [template expressions](guide/template-syntax#template-expressions) shouldn't have [side effects](guide/template-syntax#avoid-side-effects), template statements usually do. The `deleteItem()` method does have a side effect: it deletes an item. 虽然[模板表达式](guide/template-syntax#template-expressions)不应该有[副作用](guide/template-syntax#avoid-side-effects),但是模板语句通常会有。这里的 `deleteItem()` 方法就有一个副作用:它删除了一个条目。 Deleting an item updates the model, and depending on your code, triggers other changes including queries and saving to a remote server. These changes propagate through the system and ultimately display in this and other views. 删除这个英雄会更新模型,还可能触发其它修改,包括向远端服务器的查询和保存。 这些变更通过系统进行扩散,并最终显示到当前以及其它视图中。
{@a two-way} ## Two-way binding `[(...)]` ## 双向绑定 `[(...)]` Two-way binding gives your app a way to share data between a component class and its template. 双向绑定为您的应用程序提供了一种在组件类及其模板之间共享数据的方式。 For a demonstration of the syntax and code snippets in this section, see the two-way binding example. 有关本节中语法和代码段的演示,请参见 双向绑定范例。 ### Basics of two-way binding ### 双向绑定的基础知识 Two-way binding does two things: 双向绑定会做两件事: 1. Sets a specific element property. 设置特定的元素属性。 1. Listens for an element change event. 监听元素的变更事件。 Angular offers a special _two-way data binding_ syntax for this purpose, `[()]`. The `[()]` syntax combines the brackets of property binding, `[]`, with the parentheses of event binding, `()`. Angular 为此提供了一种特殊*的双向数据绑定*语法 `[()]`。`[()]` 语法将属性绑定的括号 `[]` 与事件绑定的括号 `()` 组合在一起。
[( )] = banana in a box
[( )] = 盒子里的香蕉
Visualize a *banana in a box* to remember that the parentheses go _inside_ the brackets. 想象*盒子里的香蕉*来记住方括号套圆括号。
The `[()]` syntax is easy to demonstrate when the element has a settable property called `x` and a corresponding event named `xChange`. Here's a `SizerComponent` that fits this pattern. It has a `size` value property and a companion `sizeChange` event: `[()]` 语法很容易想明白:该元素具有名为 `x` 的可设置属性和名为 `xChange` 的相应事件。 `SizerComponent` 就是用的这种模式。它具有一个名为 `size` 的值属性和一个与之相伴的 `sizeChange` 事件: The initial `size` is an input value from a property binding. Clicking the buttons increases or decreases the `size`, within min/max value constraints, and then raises, or emits, the `sizeChange` event with the adjusted size. `size` 的初始值来自属性绑定的输入值。单击按钮可在最小值/最大值范围内增大或减小 `size`,然后带上调整后的大小发出 `sizeChange` 事件。 Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `SizerComponent`: 下面的例子中,`AppComponent.fontSize` 被双向绑定到 `SizerComponent`: The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value. `AppComponent.fontSizePx` 建立初始 `SizerComponent.size` 值。 Clicking the buttons updates the `AppComponent.fontSizePx` via the two-way binding. The revised `AppComponent.fontSizePx` value flows through to the _style_ binding, making the displayed text bigger or smaller. 单击按钮就会通过双向绑定更新 `AppComponent.fontSizePx`。修改后的 `AppComponent.fontSizePx` 值将传递到*样式*绑定,从而使显示的文本更大或更小。 The two-way binding syntax is really just syntactic sugar for a _property_ binding and an _event_ binding. Angular desugars the `SizerComponent` binding into this: 双向绑定语法实际上是*属性*绑定和*事件绑定*的语法糖。 Angular 将 `SizerComponent` 的绑定分解成这样: The `$event` variable contains the payload of the `SizerComponent.sizeChange` event. Angular assigns the `$event` value to the `AppComponent.fontSizePx` when the user clicks the buttons. `$event` 变量包含了 `SizerComponent.sizeChange` 事件的荷载。 当用户点击按钮时,Angular 将 `$event` 赋值给 `AppComponent.fontSizePx`。 ### Two-way binding in forms ### 表单中的双向绑定 The two-way binding syntax is a great convenience compared to separate property and event bindings. It would be convenient to use two-way binding with HTML form elements like `` and `` 和 `` element's `value` property and `input` event: 通过分别绑定到 `` 元素的 `value` 属性和 `input` 事件,可以达到同样的效果: To streamline the syntax, the `ngModel` directive hides the details behind its own `ngModel` input and `ngModelChange` output properties: 为了简化语法, `ngModel` 指令把技术细节隐藏在其输入属性 `ngModel` 和输出属性 `ngModelChange` 的后面: The `ngModel` data property sets the element's value property and the `ngModelChange` event property listens for changes to the element's value. `ngModel` 输入属性会设置该元素的值,并通过 `ngModelChange` 的输出属性来监听元素值的变化。 #### `NgModel` and value accessors #### `NgModel` 和值访问器 The details are specific to each kind of element and therefore the `NgModel` directive only works for an element supported by a [ControlValueAccessor](api/forms/ControlValueAccessor) that adapts an element to this protocol. Angular provides *value accessors* for all of the basic HTML form elements and the [Forms](guide/forms) guide shows how to bind to them. 这些技术细节是针对每种具体元素的,因此 `NgModel` 指令仅适用于通过 [ControlValueAccessor](api/forms/ControlValueAccessor) 适配过这种协议的元素。 Angular 已经为所有基本的 HTML 表单元素提供了*值访问器*,[表单](guide/forms)一章示范了如何绑定到它们。 You can't apply `[(ngModel)]` to a non-form native element or a third-party custom component until you write a suitable value accessor. For more information, see the API documentation on [DefaultValueAccessor](https://angular.io/api/forms/DefaultValueAccessor). 在编写适当的值访问器之前,不能将 `[(ngModel)]` 应用于非表单的原生元素或第三方自定义组件。欲知详情,参见[DefaultValueAccessor](https://angular.io/api/forms/DefaultValueAccessor)上的 API 文档。 You don't need a value accessor for an Angular component that you write because you can name the value and event properties to suit Angular's basic [two-way binding syntax](guide/template-syntax#two-way) and skip `NgModel` altogether. The `sizer` in the [Two-way Binding](guide/template-syntax#two-way) section is an example of this technique. 您不一定非用为所编写的 Angular 组件提供值访问器,因为您还可以把值属性和事件属性命名为符合 Angular 的基本[双向绑定语法](guide/template-syntax#two-way)的形式,并完全跳过 `NgModel`。[双向绑定](guide/template-syntax#two-way)部分的 `sizer` 是此技术的一个示例。 Separate `ngModel` bindings are an improvement over binding to the element's native properties, but you can streamline the binding with a single declaration using the `[(ngModel)]` syntax: 单独的 `ngModel` 绑定是对绑定到元素的原生属性方式的一种改进,但您可以使用 `[(ngModel)]` 语法来通过单个声明简化绑定: This `[(ngModel)]` syntax can only _set_ a data-bound property. If you need to do something more, you can write the expanded form; for example, the following changes the `` value to uppercase: 此 `[(ngModel)]` 语法只能*设置*数据绑定属性。如果您要做得更多,可以编写扩展表单。例如,下面的代码将 `` 值更改为大写: Here are all variations in action, including the uppercase version: 这里是所有这些变体的动画,包括这个大写转换的版本:
{@a structural-directives} ## Built-in _structural_ directives ## 内置*结构型*指令 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. 结构型指令的职责是 HTML 布局。 它们塑造或重塑 DOM 的*结构*,这通常是通过添加、移除和操纵它们所附加到的宿主元素来实现的。 This section is an introduction to the common built-in structural directives: 本节会介绍常见的内置结构型指令: * [`NgIf`](guide/template-syntax#ngIf)—conditionally creates or destroys subviews from the template. [`NgIf`](guide/template-syntax#ngIf) —— 从模板中创建或销毁子视图。 * [`NgFor`](guide/template-syntax#ngFor)—repeat a node for each item in a list. [`NgFor`](guide/template-syntax#ngFor) —— 为列表中的每个条目重复渲染一个节点。 * [`NgSwitch`](guide/template-syntax#ngSwitch)—a set of directives that switch among alternative views. [`NgSwitch`](guide/template-syntax#ngSwitch) —— 一组在备用视图之间切换的指令。
The deep details of structural directives are covered in the [Structural Directives](guide/structural-directives) guide, which explains the following: [结构型指令](guide/structural-directives)一章涵盖了结构型指令的详细内容,它解释了以下内容: * Why you [prefix the directive name with an asterisk (\*)](guide/structural-directives#the-asterisk--prefix). 为什么[在要指令名称前加上星号(\*)](guide/structural-directives#the-asterisk--prefix) 。 * Using [``](guide/structural-directives#ngcontainer "") to group elements when there is no suitable host element for the directive. 当指令没有合适的宿主元素时,使用 [``](guide/structural-directives#ngcontainer "<ng-container>") 对元素进行分组。 * How to write your own structural directive. 如何写自己的结构型指令。 * That you can only apply [one structural directive](guide/structural-directives#one-per-element "one per host element") to an element. 你只能往一个元素上应用[一个结构型指令](guide/structural-directives#one-per-element "one per host element")。

{@a ngIf} ### NgIf You can add or remove an element from the DOM by applying an `NgIf` directive to a host element. Bind the directive to a condition expression like `isActive` in this example. 您可以通过将 `NgIf` 指令应用在宿主元素上来从 DOM 中添加或删除元素。在此示例中,将指令绑定到了条件表达式,例如 `isActive` 。
Don't forget the asterisk (`*`) in front of `ngIf`. For more information on the asterisk, see the [asterisk (*) prefix](guide/structural-directives#the-asterisk--prefix) section of [Structural Directives](guide/structural-directives). 不要忘了 `ngIf` 前面的星号(`*`)。有关星号的更多信息,请参见 [结构型指令](guide/structural-directives)中的[星号(\*)前缀](guide/structural-directives#the-asterisk--prefix)部分。
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, destroying that component and all of its sub-components. 当 `isActive` 表达式返回真值时,`NgIf` 会把 `ItemDetailComponent` 添加到 DOM 中。当表达式为假值时,`NgIf` 将从 DOM 中删除 `ItemDetailComponent`,从而销毁该组件及其所有子组件。 #### Show/hide vs. `NgIf` #### 显示/隐藏与 `NgIf` Hiding an element is different from removing it with `NgIf`. For comparison, the following example shows how to control the visibility of an element with a [class](guide/template-syntax#class-binding) or [style](guide/template-syntax#style-binding) binding. 隐藏元素与使用 `NgIf` 删除元素不同。为了进行比较,下面的示例演示如何使用[类](guide/template-syntax#class-binding)或[样式](guide/template-syntax#style-binding)绑定来控制元素的可见性。 When you hide an element, that element and all of its descendants remain in the DOM. All components for those elements stay in memory and Angular may continue to check for changes. You could be holding onto considerable computing resources and degrading performance unnecessarily. 隐藏元素时,该元素及其所有后代仍保留在 DOM 中。这些元素的所有组件都保留在内存中,Angular 会继续做变更检查。它可能会占用大量计算资源,并且会不必要地降低性能。 `NgIf` works differently. When `NgIf` is `false`, Angular removes the element and its descendants from the DOM. It destroys their components, freeing up resources, which results in a better user experience. `NgIf` 工作方式有所不同。如果 `NgIf` 为 `false`,则 Angular 将从 DOM 中删除该元素及其后代。这销毁了它们的组件,释放了资源,从而带来更好的用户体验。 If you are hiding large component trees, consider `NgIf` as a more efficient alternative to showing/hiding. 如果要隐藏大型组件树,请考虑使用 `NgIf` 作为显示/隐藏的更有效替代方法。
For more information on `NgIf` and `ngIfElse`, see the [API documentation about NgIf](api/common/NgIf). 有关 `NgIf` 和 `ngIfElse` 的更多信息,请参阅 [关于 NgIf 的 API 文档](api/common/NgIf)。
#### Guard against null #### 防范空指针错误 Another advantage of `ngIf` is that you can use it to guard against null. Show/hide is best suited for very simple use cases, so when you need a guard, opt instead for `ngIf`. Angular will throw an error if a nested expression tries to access a property of `null`. `ngIf` 另一个优点是您可以使用它来防范空指针错误。显示/隐藏就是最合适的极简用例,当您需要防范时,请改用 `ngIf` 代替。如果其中嵌套的表达式尝试访问 `null` 的属性,Angular 将引发错误。 The following shows `NgIf` guarding two `
`s. The `currentCustomer` name appears only when there is a `currentCustomer`. The `nullCustomer` will not be displayed as long as it is `null`. 下面的例子中 `NgIf` 保护着两个 `
`。仅当存在 `currentCustomer` 时,才会显示 `currentCustomer` 名称。除非它为 `null` 否则不会显示 `nullCustomer`。
See also the [safe navigation operator](guide/template-syntax#safe-navigation-operator "Safe navigation operator (?.)") below. 另请参见下面的[安全导航运算符](guide/template-syntax#safe-navigation-operator "安全导航运算符(?.)") 。

{@a ngFor} ### `NgFor` `NgFor` is a repeater directive—a way to present a list of items. You define a block of HTML that defines how a single item should be displayed and then you tell Angular to use that block as a template for rendering each item in the list. The text assigned to `*ngFor` is the instruction that guides the repeater process. `NgFor` 是一个重复器指令 —— 一种用来显示条目列表的方法。您定义了一个 HTML 块,该 HTML 块定义了应如何显示单个条目,然后告诉 Angular 以该块为模板来渲染列表中的每个条目。赋值给 `*ngFor` 的文本是用来指导重复器工作过程的指令。 The following example shows `NgFor` applied to a simple `
`. (Don't forget the asterisk (`*`) in front of `ngFor`.) 以下示例显示了如何将 `NgFor` 应用于简单的 `
`。 (不要忘了 `ngFor` 前面的星号(`*`)。) You can also apply an `NgFor` to a component element, as in the following example. 您还可以将 `NgFor` 应用于组件元素,如以下示例所示。 {@a microsyntax}
*ngFor microsyntax
The string assigned to `*ngFor` is not a [template expression](guide/template-syntax#template-expressions). Rather, it's a *microsyntax*—a little language of its own that Angular interprets. The string `"let item of items"` means: 赋值给 `*ngFor` 的字符串不是[模板表达式](guide/template-syntax#template-expressions) 。而是一个*微语法* —— 由 Angular 解释的一种小型语言。字符串 `"let item of items"` 的意思是: > *Take each item in the `items` array, store it in the local `item` looping variable, and make it available to the templated HTML for each iteration.* > *将 `items` 数组中的每个条目存储在局部循环变量 `item` 中,并使其可用于每次迭代的模板 HTML 中。* Angular translates this instruction into an `` 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 microsyntax, see the [Structural Directives](guide/structural-directives#microsyntax) guide. Angular 将该指令转换为包裹着宿主元素的 ``,然后反复使用此模板为列表中的每个 `item` 创建一组新的元素和绑定。有关微语法的更多信息,请参见[结构型指令](guide/structural-directives#microsyntax)一章。
{@a template-input-variable} {@a template-input-variables} #### Template input variables #### 模板输入变量 The `let` keyword before `item` creates a template input variable called `item`. The `ngFor` directive iterates over the `items` array returned by the parent component's `items` property and sets `item` to the current item from the array during each iteration. `item` 前面的 `let` 关键字创建了一个名为 `item` 的模板输入变量。 `ngFor` 指令迭代父组件的 `items` 属性所返回的 `items` 数组,并在每次迭代期间将 `item` 设置为该数组中的当前条目。 Reference `item` within the `ngFor` host element as well as within its descendants to access the item's properties. The following example references `item` first in an interpolation and then passes in a binding to the `item` property of the `` component. `ngFor` 的宿主元素及其后代中可引用 `item` ,来访问该条目的属性。以下示例首先在插值中引用 `item`,然后把一个绑定表达式传入 `` 组件的 `item` 属性。 For more information about template input variables, see [Structural Directives](guide/structural-directives#template-input-variable). 有关模板输入变量的更多信息,请参见[结构型指令](guide/structural-directives#template-input-variable) 。 #### `*ngFor` with `index` #### `*ngFor` 与 `index` The `index` property of the `NgFor` directive context returns the zero-based index of the item in each iteration. You can capture the `index` in a template input variable and use it in the template. `NgFor` 指令上下文中的 `index` 属性在每次迭代中返回该条目的从零开始的索引。 您可以在模板输入变量中捕获 `index`,并在模板中使用它。 The next example captures the `index` in a variable named `i` and displays it with the item name. 下面的例子在名为 `i` 的变量中捕获 `index` ,并将其与条目名称一起显示。
`NgFor` is implemented by the `NgForOf` directive. Read more about the other `NgForOf` context values such as `last`, `even`, and `odd` in the [NgForOf API reference](api/common/NgForOf). 要学习更多的*类似 index* 的值,例如 `last`、`even` 和 `odd`,请参阅 [NgFor API 参考](api/common/NgForOf)。
{@a trackBy} #### *ngFor with `trackBy` #### 带 `trackBy` 的 `*ngFor` If you use `NgFor` with large lists, a small change to one item, such as removing or adding an item, can trigger a cascade of DOM manipulations. For example, re-querying the server could reset a list with all new item objects, even when those items were previously displayed. In this case, Angular sees only a fresh list of new object references and has no choice but to replace the old DOM elements with all new DOM elements. 如果将 `NgFor` 与大型列表一起使用,则对某个条目的较小更改(例如删除或添加一项)就会触发一系列 DOM 操作。 例如,重新查询服务器可能会重置包含所有新条目对象的列表,即使先前已显示这些条目也是如此。在这种情况下,Angular 只能看到由新的对象引用组成的新列表,它别无选择,只能用所有新的 DOM 元素替换旧的 DOM 元素。 You can make this more efficient with `trackBy`. Add a method to the component that returns the value `NgFor` should track. In this case, that value is the hero's `id`. If the `id` has already been rendered, Angular keeps track of it and doesn't re-query the server for the same `id`. 您可以使用 `trackBy` 来让它更加高效。向该组件添加一个方法,该方法返回 `NgFor` 应该跟踪的值。这个例子中,该值是英雄的 `id` 。如果 `id` 已经被渲染,Angular 就会跟踪它,而不会重新向服务器查询相同的 `id` 。 In the microsyntax expression, set `trackBy` to the `trackByItems()` method. 在微语法表达式中,将 `trackBy` 设置为 `trackByItems()` 方法。 Here is an illustration of the `trackBy` effect. "Reset items" creates new items with the same `item.id`s. "Change ids" creates new items with new `item.id`s. 这就是 `trackBy` 效果的说明。 “Reset items” 将创建具有相同 `item.id` 的新条目。 “Change ids” 将使用新的 `item.id` 创建新条目。 * With no `trackBy`, both buttons trigger complete DOM element replacement. 如果没有 `trackBy`,这些按钮都会触发完全的 DOM 元素替换。 * With `trackBy`, only changing the `id` triggers element replacement. 有了 `trackBy`,则只有修改了 `id` 的按钮才会触发元素替换。
Built-in directives use only public APIs; that is, they do not have special access to any private APIs that other directives can't access. 内置指令仅仅使用了公共 API。也就是说,它们没有用到任何其他指令无权访问的私有 API。

{@a ngSwitch} ## The `NgSwitch` directives ## `NgSwitch` 指令 NgSwitch is like the JavaScript `switch` statement. It displays one element from among several possible elements, based on a switch condition. Angular puts only the selected element into the DOM. NgSwitch 类似于 JavaScript `switch` 语句。它根据切换条件显示几个可能的元素中的一个。 Angular 只会将选定的元素放入 DOM。 `NgSwitch` is actually a set of three, cooperating directives: `NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault` as in the following example. `NgSwitch` 实际上是三个协作指令的集合: `NgSwitch` , `NgSwitchCase` 和 `NgSwitchDefault`,如以下示例所示。 `NgSwitch` is the controller directive. Bind it 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. `NgSwitch` 是控制器指令。把它绑定到一个返回*开关值*的表达式,例如 `feature` 。尽管此示例中的 `feature` 值是字符串,但开关值可以是任何类型。 **Bind to `[ngSwitch]`**. You'll get an error if you try to set `*ngSwitch` because `NgSwitch` is an *attribute* directive, not a *structural* directive. Rather than touching the DOM directly, it changes the behavior of its companion directives. **绑定到 `[ngSwitch]`** 。如果试图写成 `*ngSwitch`,就会出现错误,因为 `NgSwitch` 是*属性型*指令,而不是*结构型*指令。它不会直接接触 DOM,而是会更改与之相伴的指令的行为。 **Bind to `*ngSwitchCase` and `*ngSwitchDefault`**. The `NgSwitchCase` and `NgSwitchDefault` directives are _structural_ directives because they add or remove elements from the DOM. **绑定到 `*ngSwitchCase` 和 `*ngSwitchDefault`** `NgSwitchCase` 和 `NgSwitchDefault` 指令都是*结构型指令*,因为它们会从 DOM 中添加或移除元素。 * `NgSwitchCase` 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. 当 `NgSwitchCase` 的绑定值等于开关值时,就将其元素添加到 DOM 中;否则从 DOM 中删除。 * `NgSwitchDefault` adds its element to the DOM when there is no selected `NgSwitchCase`. `NgSwitchDefault` 会在没有任何一个 `NgSwitchCase` 被选中时把它所在的元素加入 DOM 中。 The switch directives are particularly useful for adding and removing *component elements*. This example switches among four `item` components defined in the `item-switch.components.ts` file. Each component has an `item` [input property](guide/template-syntax#inputs-outputs "Input property") which is bound to the `currentItem` of the parent component. 开关指令对于添加和删除*组件元素*特别有用。本示例在 `item-switch.components.ts` 文件中定义的四个 `item` 组件之间切换。每个组件都有一个名叫 `item` 的[输入属性](guide/template-syntax#inputs-outputs "输入属性") ,它会绑定到父组件的 `currentItem` 。 Switch directives work as well with native elements and web components too. For example, you could replace the `` switch case with the following. 开关指令也同样适用于原生元素和 Web Component。 比如,你可以把 `` 分支替换为如下代码。
{@a template-reference-variable} {@a template-reference-variables--var-} {@a ref-vars} {@a ref-var} ## Template reference variables (`#var`) ## 模板引用变量( `#var` ) A **template reference variable** is often a reference to a DOM element within a template. It can also refer to a directive (which contains a component), an element, [TemplateRef](api/core/TemplateRef), or a web component. **模板引用变量**通常是对模板中 DOM 元素的引用。它还可以引用指令(包含组件)、元素、[TemplateRef](api/core/TemplateRef) 或 [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components "MDN:Web Component") 。 For a demonstration of the syntax and code snippets in this section, see the template reference variables example. 有关本节中语法和代码段的演示,请参见模板参考变量示例。 Use the hash symbol (#) to declare a reference variable. The following reference variable, `#phone`, declares a `phone` variable on an `` element. 使用井号(#)声明模板引用变量。以下模板引用变量 `#phone` 会在 `` 元素上声明了一个 `phone` 变量。 You can refer to a template reference variable anywhere in the component's template. Here, a `