ng-book札记——Angular工作方式
Angular应用由组件(Component)构成。它与AngularJS中的指令相似(directive)。
应用
一个Angular应用本质上是一个组件树。在组件树的顶层,最上级的组件即是应用本身。当启动此应用时,浏览器将渲染这个顶层组件。
Angular组件的重要特性是其可按照父子树的结构*组合,当每个组件渲染时,也会递归渲染其子组件。
假设有一个库存管理的应用,如下图所示:
在开始写应用时,首先应该将其拆成三个组件。
标签导航组件:
面包屑导航组件:
产品列表组件:
再进一步拆分的话,产品列表由多个产品行构成。
而产品行又可以拆成产品图片,产品所属,价格显示这件小组件。
所以最终应用的树图是这样的:
组件
每个组件包含三部分:
- 组件装饰器(Component Decorator)
- 视图(View)
- 控制器(Controller)
以最上层的应用组件为例,这个组件的代码可能是这样的:
@Component({ selector: 'inventory-app-root', template: ` <div class="inventory-app"> (Products will go here soon) </div> ` }) export class AppComponent { }
@Component
就是组件装饰器,它为AppComponent类添加元数据。
上例的@Component
装饰器指定了选择器(selector)——告诉Angular匹配何种元素(element),以及模板(template)——定义了视图。
模板内容可以置于其它的文件中,这时需要使用templateUrl替代template。
@Component({ selector: 'inventory-app-root', templateUrl: './app.component.html' }) export class AppComponent { }
组件控制器通过类(class)来定义,上例的AppComponent类即是控制器。
假设要在AppComponent组件对应的视图中显示产品的信息,可以通过模板绑定的方式达成此目的。
<div class="inventory-app"> <h1>{{ product.name }}</h1> <span>{{ product.sku }}</span> </div>
{{ … }}语法被称为模板绑定,它会告诉视图使用模板中的特定数据。
组件中的核心特性之一是输入(input)与输出(output)。
<div class="inventory-app"> <products-list [productList]="products" (onProductSelected)="productWasSelected($event)"> </products-list> </div>
方括号传送输入,圆括号处理输出。
借由输入绑定数据进入组件,通过输出绑定事件流出组件。
在Angular中,父组件通过输入传送数据给子组件,而子组件则通过输出传送数据给父组件。
需要接收数据的子组件要由@Input()
装饰器指明对应的属性。如下例:
import { Component, Input } from '@angular/core'; @Component({ selector: 'my-component', }) class MyComponent { @Input() name: string; @Input() age: number; }
而要让父组件接收数据的子组件要使用@output()
装饰器。
@Component({ selector: 'single-component', template: ` <button (click)="liked()">Like it?</button> ` }) class SingleComponent { @Output() putRingOnIt: EventEmitter<string>; constructor() { this.putRingOnIt = new EventEmitter(); } liked(): void { this.putRingOnIt.emit("oh oh oh"); } }
例子中的子组件需要完成三步操作,指定输出属性(使用@output()
标注);创建EventEmitter对象并绑定到对应输出属性;当特定方法(比如liked())被调用时发出事件。
@Component({ selector: 'club', template: ` <div> <single-component (putRingOnIt)="ringWasPlaced($event)" ></single-component> </div> ` }) class ClubComponent { ringWasPlaced(message: string) { console.log(`Put your hands up: ${message}`); } }
父组件中$event包含了由子组件传回的数据。