| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  | block includes | 
					
						
							|  |  |  |  |   include ../_util-fns | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   One of the defining features of a single page application is its manipulation | 
					
						
							|  |  |  |  |   of the DOM tree. Instead of serving a whole new page every time a user | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   navigates, whole sections of the DOM appear and disappear according | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   to the application state. In this chapter we'll to look at how Angular | 
					
						
							|  |  |  |  |   manipulates the DOM and how we can do it ourselves in our own directives. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   单页面应用的基本特性之一,就是它要操纵DOM树。不同于以前那种用户每次浏览都重新从服务器取得整个页面的方式, | 
					
						
							|  |  |  |  |   单页面应用中,DOM中的各个区域会根据应用程序的状态而出现或消失。 | 
					
						
							|  |  |  |  |   在本章中,我们将看看Angular如何操纵DOM树,以及我们该如何在自己的指令中这么做。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   In this chapter we will | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   在本章中,我们将: | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   - [learn what structural directives are](#definition) | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   - [学习什么是结构型(structural)指令](#definition) | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |   - [study *ngIf*](#ngIf) | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   - [研究*ngIf*](#ngIf) | 
					
						
							| 
									
										
										
										
											2016-06-11 21:59:43 +08:00
										 |  |  |  |   - [discover the `<template>` element](#template) | 
					
						
							|  |  |  |  |   - [`<template>`元素揭秘](#template) | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   - [understand the asterisk (\*) in **ngFor*](#asterisk) | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   - [理解**ngFor*中的星号(\*)](#asterisk) | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   - [write our own structural directive](#unless) | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   - [写我们自己的结构型指令](#unless) | 
					
						
							| 
									
										
										
										
											2016-05-20 16:18:58 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-03 17:11:17 -07:00
										 |  |  |  |   Try the <live-example></live-example>. | 
					
						
							| 
									
										
										
										
											2016-07-07 08:15:51 +08:00
										 |  |  |  |    | 
					
						
							|  |  |  |  |   试试<live-example></live-example>。 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | <a id="definition"></a> | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## What are structural directives? | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   ## 什么是结构型指令? | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   There are three kinds of Angular directives: | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Angular指令可分为三种: | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   1. Components | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   1. 组件 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   1. Attribute directives | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   1. 属性型指令 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   1. Structural directives | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   1. 结构型指令 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   The *Component* is really a directive with a template. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   It's the most common of the three directives and we write lots of them as we build our application. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   *组件*其实就是一个带模板的指令。 | 
					
						
							|  |  |  |  |   它是这三种指令中最常用的,我们会写大量的组件来构建应用程序。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   The [*Attribute* directive](attribute-directives.html) changes the appearance or behavior of an element. | 
					
						
							| 
									
										
										
										
											2016-01-03 18:03:37 +00:00
										 |  |  |  |   The built-in [NgStyle](template-syntax.html#ngStyle) directive, for example, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   can change several element styles at the same time. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   We can use it to render text bold, italic, and lime green by binding to a | 
					
						
							|  |  |  |  |   component property that requests such a sickening result. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   [*属性型*指令](attribute-directives.html)会修改元素的外观或行为。 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:46:17 +08:00
										 |  |  |  |   比如,内置指令[NgStyle](template-syntax.html#ngStyle)就能同时修改元素的好几个样式。 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   通过绑定到组件的属性,我们可以把文本渲染成加粗、斜体、灰绿色这种肉麻的效果。 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   A *Structural* directive changes the DOM layout by adding and removing DOM elements. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   We've seen three of the built-in structural directives in other chapters: [ngIf](template-syntax.html#ngIf), | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   [ngSwitch](template-syntax.html#ngSwitch) and [ngFor](template-syntax.html#ngFor). | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   *结构型*指令通过添加和删除DOM元素来改变DOM的布局。 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:46:17 +08:00
										 |  |  |  |   我们会在其它章节看到三个内置的结构型指令:[ngIf](template-syntax.html#ngIf)、 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   [ngSwitch](template-syntax.html#ngSwitch)以及[ngFor](template-syntax.html#ngFor)。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/structural-directives.component.html', 'structural-directives')(format=".") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  | <a id="ngIf"></a> | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | .l-main-section | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## NgIf Case Study | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   ## NgIf案例分析 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Let’s focus on `ngIf`. It's a great example of a structural | 
					
						
							|  |  |  |  |   directive: it takes a boolean and makes an entire chunk of DOM appear | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   or disappear. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 08:35:02 +08:00
										 |  |  |  |   我们重点看下`ngIf`。它是一个很好的结构型指令案例:它接受一个布尔值,并据此让一整块DOM树出现或消失。 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/structural-directives.component.html', 'ngIf')(format=".") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   The `ngIf` directive does not hide the element. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Using browser developer tools we can see that, when the condition is true, the top | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   paragraph is in the DOM and the bottom disused paragraph is completely | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   absent from the DOM! In its place are empty `<script>` tags. | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   `ngIf`指令并不会隐藏元素。 | 
					
						
							|  |  |  |  |   使用浏览器的开发者工具就会看到:当`condition`为真的时候,只剩下了DOM顶部的段落,而底部无用的段落完全从DOM中消失了! | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   在它的位置上是空白的`<script>`标签 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |   img(src='/resources/images/devguide/structural-directives/element-not-in-dom.png' alt="element not in dom") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Why *remove* rather than *hide*? | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   ### 为什么*移除*而不是*隐藏*? | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   We could hide the unwanted paragraph by setting its css `display` style to `none`. | 
					
						
							|  |  |  |  |   The element would remain in the DOM while invisible. Instead we removed it with `ngIf`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   其实也可以通过把CSS样式`display`设置为`none`来隐藏掉那个不想要的段落。 | 
					
						
							|  |  |  |  |   该元素仍然留在DOM中,只是看不到了。但我们却通过`ngIf`移除了它。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   The difference matters. When we hide an element, | 
					
						
							|  |  |  |  |   the component's behavior continues. | 
					
						
							|  |  |  |  |   It remains attached to its DOM element. It continues to listen to events. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Angular keeps checking for changes that could affect data bindings. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Whatever the component was doing it keeps doing. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   不同之处在于:当我们隐藏掉一个元素时,组件的行为还在继续 —— 它仍然附加在它所属的DOM元素上, | 
					
						
							|  |  |  |  |   它也仍在监听事件。Angular会继续检查哪些能影响数据绑定的变更。 | 
					
						
							|  |  |  |  |   组件原本要做的那些事情仍在继续。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Although invisible, the component — and all of its descendent components — | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   tie up resources that might be more useful elsewhere. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   The performance and memory burden can be substantial and the user may not benefit at all. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   虽然不可见,组件及其各级子组件仍然占用着资源,而这些资源如果分配给别人可能会更有用。 | 
					
						
							|  |  |  |  |   在性能和内存方面的负担相当可观,而用户却可能无法从中受益。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   On the positive side, showing the element again is very quick. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   The component's previous state is preserved and ready to display. | 
					
						
							|  |  |  |  |   The component doesn't re-initialize — an operation that could be expensive. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  |   当然,从积极的一面看,重新显示这个元素会非常快。 | 
					
						
							|  |  |  |  |   组件以前的状态被保留着,并随时可以显示。 | 
					
						
							|  |  |  |  |   组件不用重新初始化 —— 该操作可能会比较昂贵。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   `ngIf` is different. | 
					
						
							|  |  |  |  |   Setting `ngIf` to false **does** affect the component's resource consumption. | 
					
						
							|  |  |  |  |   Angular removes the element from DOM, stops change detection for the associated component, | 
					
						
							|  |  |  |  |   detaches it from DOM events (the attachments that it made) and destroys the component. | 
					
						
							|  |  |  |  |   The component can be garbage-collected (we hope) and free up memory. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   而`ngIf`不同。 | 
					
						
							|  |  |  |  |   把`ngIf`设置为假**将会**影响到组件的资源消耗。 | 
					
						
							|  |  |  |  |   Angular会从DOM中移除该元素,停止相关组件的变更检测,把它从DOM事件中摘掉(事件是组件造成的附加项),并销毁组件。 | 
					
						
							|  |  |  |  |   组件会被垃圾回收(希望如此)并释放内存。 | 
					
						
							| 
									
										
										
										
											2016-05-28 10:44:47 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Components often have child components which themselves have children. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   All of them are destroyed when `ngIf` destroys the common ancestor. | 
					
						
							|  |  |  |  |   This cleanup effort is usually a good thing. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   组件通常还有子组件,子组件还有自己的子组件。 | 
					
						
							|  |  |  |  |   当`ngIf`销毁这个祖先组件时,它们全都会被销毁。 | 
					
						
							|  |  |  |  |   这种清理工作通常会是好事。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Of course it isn't *always* a good thing. | 
					
						
							|  |  |  |  |   It might be a bad thing if we need that particular component again soon. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   当然,它也并不*总是*好事。 | 
					
						
							|  |  |  |  |   如果我们很快就会再次需要这个组件,它就变成坏事了。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   The component's state might be expensive to re-construct. | 
					
						
							|  |  |  |  |   When `ngIf` becomes `true` again, Angular recreates the component and its subtree. | 
					
						
							|  |  |  |  |   Angular runs every component's initialization logic again. That could be expensive ... as when | 
					
						
							|  |  |  |  |   a component re-fetches data that had been in memory just moments ago. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   重建组件的状态可能是昂贵的。 | 
					
						
							|  |  |  |  |   当`ngIf`重新变为`true`的时候,Angular会重新创建该组件及其子树。 | 
					
						
							|  |  |  |  |   Angular会重新运行每个组件的初始化逻辑。那可能会很昂贵……比如当组件需要重新获取刚刚还在内存中的数据时。 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |     *Design thought*: minimize initialization effort and consider caching state in a | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |     companion service. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     *设计思路*:要最小化初始化的成本,并考虑把状态缓存在一个伴生的服务中。 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Although there are pros and cons to each approach, | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   in general it is best to use `ngIf` to remove unwanted components rather than | 
					
						
							|  |  |  |  |   hide them. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   虽然每种方法都有各自的优点和缺点,但使用`ngIf`来移除不需要的组件通常都会比隐藏它们更好一些。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   **These same considerations apply to every structural directive, whether built-in or custom.** | 
					
						
							|  |  |  |  |   We should ask ourselves — and the users of our directives — to think carefully | 
					
						
							|  |  |  |  |   about the consequences of adding and removing elements and of creating and destroying components. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:46:17 +08:00
										 |  |  |  |   **同样的考量也适用于每一个结构型指令,无论是内置的还是自定义的。** | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   我们应该提醒自己以及我们指令的使用者,来仔细考虑添加元素、移除元素以及创建和销毁组件的后果。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Let's see these dynamics at work. For fun, we'll stack the deck *against* | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   our recommendation and consider a component called `heavy-loader` that | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   ***pretends*** to load a ton of data when initialized. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 09:26:54 +08:00
										 |  |  |  |   让我们在实践中看看这些变化。为了娱乐,我们设想在甲板上有个叫`heavy-loader`(重型起重机)的组件,它会***假装***在初始化时装载一吨数据。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   We'll display two instances of the component.  We toggle the visibility of the first one with CSS. | 
					
						
							|  |  |  |  |   We toggle the second into and out of the DOM with `ngIf`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   我们将显示该组件的两个实例。我们使用CSS切换第一个实例的可见性,用`ngIf`把第二个实例添加到DOM和将其移除。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeTabs( | 
					
						
							|  |  |  |  |     `structural-directives/ts/app/structural-directives.component.html, | 
					
						
							|  |  |  |  |     structural-directives/ts/app/heavy-loader.component.ts`, | 
					
						
							|  |  |  |  |     'message-log,', | 
					
						
							| 
									
										
										
										
											2016-05-06 07:42:01 -07:00
										 |  |  |  |     'template (excerpt), heavy-loader.component.ts') | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   We also log when a component is created or destroyed | 
					
						
							|  |  |  |  |   using the built-in `ngOnInit` and `ngOnDestroy` [lifecycle hooks](lifecycle-hooks.html). | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Here it is in action: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:46:17 +08:00
										 |  |  |  |   借助内置的`ngOnInit`和`ngOnDestroy`[生命周期钩子](lifecycle-hooks.html),我们同时记录了组件的创建或销毁过程。 | 
					
						
							| 
									
										
										
										
											2016-06-17 23:13:23 +08:00
										 |  |  |  |   下面是它的操作演示: | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |   img(src='/resources/images/devguide/structural-directives/heavy-loader-toggle.gif' alt="heavy loader toggle") | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Both components are in the DOM at the start. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   First we toggle the component's visibility repeatedly. The component never leaves the DOM. | 
					
						
							|  |  |  |  |   When visible it's always the same instance and the log is quiet. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   开始的时候,两个组件都在DOM中。 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   首先我们重复切换第一个组件的可见性。组件从未离开过DOM节点。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   当可见时,它总是同一个实例,而日志里什么都没有。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Then we toggle the second component with `ngIf`. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   We create a new instance every time and the log shows that we're paying | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   a heavy price to create and destroy it. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   当我们切换使用`ngIf`的第二个实例时。 | 
					
						
							|  |  |  |  |   我们每次都会创建新的实例,而日志中显示,我们为了创建和销毁它付出了沉重的代价。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   If we really expected to "wink" the component like this, toggling visibility would be the better choice. | 
					
						
							|  |  |  |  |   In most UIs, when we "close" a component we're unlikely see it again for a long time, if ever. | 
					
						
							|  |  |  |  |   The `ngIf` would be preferred in that case. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   如果我们真的期望像这样让组件“眨眼”,切换可见性就会是更好的选择。 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   在大多数UI中,当我们“关闭”一个组件时,在相当长时间内都不大可能想再见到它 —— 可能永远也不见。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   在这种情况下,我们会更喜欢`ngIf`。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | <a id="template"></a> | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## The *<template>* tag | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   ## *<template>*标签 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Structural directives, like `ngIf`, do their magic by using the | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   [HTML 5 template tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   结构型指令,比如`ngIf`,使用[HTML 5的template标签](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) | 
					
						
							|  |  |  |  |   完成它们的“魔法”。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   Outside of an Angular app, the `<template>` tag's default CSS `display` property is `none`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   It's contents are ***invisible*** within | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   a hidden [document fragment](https://developer.mozilla.org/en/docs/Web/API/DocumentFragment). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   在Angular应用之外,`<template>`标签的默认CSS属性`display`是`none`。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   它的内容存在于一个***隐藏的***[文档片段](https://developer.mozilla.org/en/docs/Web/API/DocumentFragment)中。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   Inside of an app, Angular ***removes*** the`<template>` tags and their children. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   The contents are gone — but not forgotten as we'll see soon. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   而在Angular应用中,Angular会***移除***`<template>`标签及其子元素。 | 
					
						
							|  |  |  |  |   这些内容不见了,但是并没有被“忘记”,我们很快就明白了。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   We can confirm these effects by wrapping the middle "hip" of the phrase "Hip! Hip! Hooray!" within a `<template>` tag. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   我们可以通过把短语"Hip! Hip! Hooray!"中间的"hip"包在一个`<template>`标签中来验证下这个效果。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | +makeExample('structural-directives/ts/app/structural-directives.component.html', 'template-tag')(format=".") | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |   The display is a 'Hip! Hooray!', short of perfect enthusiasm. The DOM effects are different when Angular is in control. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 09:26:54 +08:00
										 |  |  |  |   这时候显示的内容是'Hip! Hooray!',缺乏完美的热情(译注:因为少了一个词嘛)。在Angular的控制下,DOM的效果是不同的。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | figure.image-display | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   img(src='/resources/images/devguide/structural-directives/template-in-out-of-a2.png' alt="template outside angular") | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   Evidently Angular replaces the `<template>` tag and its contents with empty `<script>` tags. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   That's just its default behavior. | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   It can do something different as we saw when applying a variety of `ngSwitch` directives to `<template>` tags: | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   显然,Angular把`<template>`标签及其内容替换成了一个空白的`<script>`标签。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   这只是它的默认行为。 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   当把`ngSwitch`家族的各种指令应用于`<template>`标签时,我们就会看到有些东西不一样了: | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExample('structural-directives/ts/app/structural-directives.component.html', 'ngSwitch')(format=".") | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   When one of those `ngSwitch` conditions is true, Angular inserts the template's content into the DOM. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   当这些`ngSwitch`的条件之一为真的时候,Angular把模板的内容插入到了DOM中。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   What does this have to do with `ngIf` and `ngFor`?  We didn't use a `<template>` tag with those directives. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   这和`ngIf`和`ngFor`有什么关系?很明显,我们在那些指令中并没有用到`<template>`标签。 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | <a id="asterisk"></a> | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## The asterisk (\*) effect | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   ## 星号(\*)效果 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Here are those directives again. See the difference? | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   下面也是那些指令。看出有什么不同了吗? | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/structural-directives.component.html', 'asterisk')(format=".") | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   We're prefixing these directive names with an asterisk (\*). | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   我们把那些指令名加上了星号(\*)前缀。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   The asterisk is "syntactic sugar". It simplifies `ngIf` and `ngFor` for both the writer and the reader. | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   Under the hood, Angular replaces the asterisk version with a more verbose `<template>` form. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   这个星号是一种“语法糖”。它简化了`ngIf`和`ngFor` —— 无论是写还是读。 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   The next two `ngIf` examples are effectively the same and we may write in either style: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   接下来这两个`ngIf`范例的效果完全相同,只是我们写成了另一种风格: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/structural-directives.component.html', 'ngIf-template')(format=".") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Most of us would rather write in style (A). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   大多数都喜欢用风格(A)来写。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   It's worth knowing that Angular expands style (A) into style (B). | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   It moves the paragraph and its contents inside a `<template>` tag. | 
					
						
							|  |  |  |  |   It moves the directive up to the `<template>` tag where it becomes a property binding, | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   surrounded in square brackets. The boolean value of the host component's `condition` property | 
					
						
							|  |  |  |  |   determines whether the templated content is displayed or not. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   要知道,Angular会把风格(A)写成风格(B)。 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   它把段落及其内容移到了`<template>`标签中。 | 
					
						
							|  |  |  |  |   它把指令移到了`<template>`标签上,成为该标签的一个属性绑定 —— 包装在方括号中。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   宿主组件的`condition`属性的布尔值决定该模板的内容是否应该被显示。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Angular transforms `*ngFor` in a similar manner: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   Angular把`*ngFor`转换成一个类似的形式: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/structural-directives.component.html', 'ngFor-template')(format=".") | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   The basic pattern is the same:  create a `<template>`, relocate the content, | 
					
						
							|  |  |  |  |   and move the directive onto the `<template>`. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   基本的转换模式是一样的:创建一个`<template>`,将内容重定位,并且把指令移到`<template>`上。 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   There are extra nuances stemming from | 
					
						
							| 
									
										
										
										
											2016-04-28 11:18:52 -07:00
										 |  |  |  |   Angular's [ngFor micro-syntax](template-syntax.html#ngForMicrosyntax) which expands | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   into an additional `ngForOf` property binding (the iterable) and | 
					
						
							| 
									
										
										
										
											2016-04-28 11:18:52 -07:00
										 |  |  |  |   the `hero` template input variable (the current item in each iteration). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   Angular的[ngFor微语法](template-syntax.html#ngForMicrosyntax)里面有一些细微差别, | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   它被展开成了额外的`ngForOf`属性绑定(可迭代者)和一个模板输入变量`hero`(每次迭代中的当前条目)。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | <a id="unless"></a> | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Make a structural directive | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   ## 制作一个结构型指令 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Let's write our own structural directive, an `Unless` directive, the not-so-evil twin of `ngIf`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   我们来写自己的结构型指令:`Unless`,这是`ngIf`指令不那么邪恶的孪生兄弟。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Unlike `ngIf` which displays the template content when `true`, | 
					
						
							|  |  |  |  |   our directive displays the content when the condition is ***false***. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   当条件为`true`时`ngIf`才显示模板内容,与之不同的是,我们这个指令只有当条件是***false***时才显示这些内容。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  | block unless-intro | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     Creating a directive is similar to creating a component. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     创建指令很像创建组件。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |     * import the `Directive` decorator. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     * 导入`Directive`装饰器。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |     * add a CSS **attribute selector** (in brackets) that identifies our directive. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     * 添加一个CSS**属性选择器**(括号中),来标记出我们的指令。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |     * specify the name of the public `input` property for binding | 
					
						
							|  |  |  |  |     (typically the name of the directive itself). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 09:26:54 +08:00
										 |  |  |  |     * 指定`input`属性用于绑定的公开名称(通常就是指令自己的名字)。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |     * apply the decorator to our implementation class. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     * 把这个装饰器应用到我们的实现类上。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |     Here is how we begin: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     下面是最初的样子: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/unless.directive.ts', 'unless-declaration', 'unless.directive.ts (excerpt)')(format=".") | 
					
						
							|  |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     ### Selector brackets [ ] | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     ### 选择器中的括号[ ] | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |     The CSS syntax for selecting an attribute is a name in square brackets. | 
					
						
							| 
									
										
										
										
											2015-12-16 12:20:50 -08:00
										 |  |  |  |     We surround our directive name in square brackets. See *Directive configuration* on the | 
					
						
							|  |  |  |  |     [cheatsheet](cheatsheet.html). | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     在CSS中,用于选择属性(Attribute)的选择器就是放在方括号中的名字。 | 
					
						
							|  |  |  |  |     于是我们把指令名包裹在方括号中。参见[小抄](cheatsheet.html)中的*指令配置项*。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |     ### Selector name prefixes | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     ### 选择器名称前缀 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     We recommend picking a selector name with a prefix to ensure | 
					
						
							|  |  |  |  |     that it cannot conflict with any standard HTML attribute, now or in the future. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     我们建议在给选择器起名时加个前缀,以确保它不会和任何标准的HTML属性冲突,无论是现在还是未来。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |     We do **not** prefix our `unless` directive name with **`ng`**. | 
					
						
							|  |  |  |  |     That prefix belongs to Angular and | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |     we don't want to confuse our directives with their directives. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |     我们**并没有**给`unless`指令名加上**`ng`**前缀。 | 
					
						
							| 
									
										
										
										
											2016-09-17 11:46:17 +08:00
										 |  |  |  |     那个前缀是属于Angular的,我们肯定不会希望自己的指令和Angular内置的指令冲突。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |     Our prefix is `my`. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     我们用的前缀是`my`。 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   We'll need access to the template *and* something that can render its contents. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   We access the template with a `TemplateRef`.  The renderer is a `ViewContainerRef`. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   We inject both into our constructor as private variables. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   我们需要访问模板,并且*还*需要一个渲染器来渲染它的内容。 | 
					
						
							|  |  |  |  |   我们通过`TemplateRef`来访问模板。渲染器是`ViewContainerRef`。 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   我们把它们都作为私有变量注入到构造函数中。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/unless.directive.ts', 'unless-constructor')(format=".") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |   The consumer of our directive will bind a boolean value to our directive's `myUnless` input property. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   The directive adds or removes the template based on that value. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   这个指令的使用者将把一个布尔值绑定到指令的输入属性`myUnless`上。 | 
					
						
							|  |  |  |  |   该指令会基于这个值添加或移除此模板。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |   Let's add the `myUnless` property now as a setter-only property. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   我们现在先把`myUnless`属性定义成一个“只写”属性。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/unless.directive.ts', 'unless-set')(format=".") | 
					
						
							|  |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |     The `@Input()` annotation marks this property as an input for the directive. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     `@Input()`装饰器表明这个属性对于指令来说是个输入属性。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Nothing fancy here: if the condition is false, | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   we render the template, otherwise we clear the element content. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   这里没什么特别的:如果条件为假,我们就渲染模板,否则就清空元素内容。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |   The end result should look like this: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   最终看起来是这样的: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/unless.directive.ts', null, 'unless.directive.ts') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-09 17:38:25 +01:00
										 |  |  |  |   Now we add it to the `declarations` array of the AppModule and try it. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   First we add some test HTML to the template: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   现在,我们就来把它加到宿主组件的`directives`数组中,试一试。 | 
					
						
							|  |  |  |  |   我们首先把一些测试用的HTML添加到模板中: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeExample('structural-directives/ts/app/structural-directives.component.html', 'myUnless')(format=".") | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   We run it and it behaves as expected, doing the opposite of `ngIf`. | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   When `condition` is `true`, the top paragraph is removed (replaced by `<script>` tags) and the bottom paragraph appears. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   我们运行它,它的行为正如所预期的那样 —— 跟`ngIf`相反。 | 
					
						
							|  |  |  |  |   当`condition`为`true`时,顶部的段落被移除了(被替换为`<script>`标签),并且底部的段落显示了出来。 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |   img(src='/resources/images/devguide/structural-directives/myUnless-is-true.png' alt="myUnless is true" ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Our `myUnless` directive is dead simple. Surely we left something out. | 
					
						
							|  |  |  |  |   Surely `ngIf` is more complex? | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   这个`myUnless`指令实在太简单了,我们肯定忘了点什么。 | 
					
						
							|  |  |  |  |   那么`ngIf`会更复杂吗? | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 05:18:38 -07:00
										 |  |  |  |   [Look at the source code](https://github.com/angular/angular/blob/master/modules/%40angular/common/src/directives/ng_if.ts). | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   It's well documented and we shouldn't be shy | 
					
						
							|  |  |  |  |   about consulting the source when we want to know how something works. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   [看下源码](https://github.com/angular/angular/blob/master/modules/%40angular/common/src/directives/ng_if.ts)。 | 
					
						
							|  |  |  |  |   它有很好的文档,况且,如果我们想了解某些东西的工作原理,也不用羞于“咨询”源码。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   `ngIf` isn't much different! There are a few | 
					
						
							|  |  |  |  |   additional checks to improve performance (don't clear or recreate the | 
					
						
							|  |  |  |  |   view unless necessary) but otherwise it's much the same. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   `ngIf`也没多大不同嘛!它做了一些额外的检查来提升性能(除非必要,否则它不会清除或重新创建视图),但其它的部分都跟我们写的一样。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | .l-main-section | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Wrap up | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   ## 总结 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   Here is the pertinent source for this chapter. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   本章相关的代码如下: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  | +makeTabs(` | 
					
						
							|  |  |  |  |   structural-directives/ts/app/unless.directive.ts, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   structural-directives/ts/app/heavy-loader.component.ts, | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   structural-directives/ts/app/structural-directives.component.ts, | 
					
						
							|  |  |  |  |   structural-directives/ts/app/structural-directives.component.html | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   `, | 
					
						
							|  |  |  |  |   null, | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   `unless.directive.ts, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |    heavy-loader.component.ts, | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |    structural-directives.component.ts, | 
					
						
							|  |  |  |  |    structural-directives.component.html | 
					
						
							|  |  |  |  |    `) | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   We learned that we can manipulate our HTML layout with | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   structural directives like `ngFor` and `ngIf` and we | 
					
						
							|  |  |  |  |   wrote our own structural directive, `myUnless`, to do something similar. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   我们学会了通过像`ngFor`和`ngIf`这样的结构型指令来操纵HTML的布局。我们还写出了我们的第一个结构型指令`myUnless`来做类似的事情。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Angular offers more sophisticated techniques for managing layout | 
					
						
							|  |  |  |  |   such as *structural components* that can take external content | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  |   and incorporate that content within their own templates. | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   Tab and tab pane controls are good examples. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  |   Angular提供了更多成熟的技术来管理布局,比如*结构性组件*可以接受外部内容,并把这些内容合并到组件自己的模板中。 | 
					
						
							|  |  |  |  |   多页标签及其面板控件就是很好的例子。 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-13 14:47:42 +00:00
										 |  |  |  |   We'll learn about structural components in a future chapter. | 
					
						
							| 
									
										
										
										
											2016-05-28 14:31:05 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 16:30:20 +01:00
										 |  |  |  |   我们将在未来的章节中还会讲述结构型指令。 |