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包含了由子组件传回的数据。

posted @ 2018-04-01 22:38  Ken.W  阅读(282)  评论(0编辑  收藏  举报