Angular 2 之三 组件

概述

Angular 2应用由组件构成;和DOM树类似,Angular 2应用是一颗组件树。

Angular 2将更新模型(Model)和在视图(View)中显示模型分在不同阶段实现:开发者负责更新模型,Angular 2通过变更检测自动更新对应的视图。

Angular 2使用属性绑定在视图中显示模型,使用事件绑定触发事件处理函数(相当于Control),事件处理函数中可以更新模型。

由此可见,Model-View-Control间的数据流是单向的,即:

  • 变更检测自动将Model状态显示在View上
  • 用户操作View触发Control
  • Control中更改Model。

对组件而言,属性绑定是输入,使用@Input标注定义,[]语法调用;事件绑定是输出,使用@Output标注定义,()语法调用。属性绑定和事件绑定是父子组件间最常用交互方式。

组件定义

组件定义使用@Component标注,元数据说明如下:

  • selector: 定义声明式组件的元素名称
  • template: 视图模板字符串
  • templateUrl: 视图模板URL,即外部模板文件
  • styles: 本组件使用的样式表列表
  • styleUrls: 本组件使用的样式表URL列表
  • directives: 本组件模板用到的Directive(和Componet)列表
  • pipes: 本组件模板用到的Pipe列表
  • providers: 组件级依赖注入的服务列表
  • viewProviders: 仅在本组件使用的依赖注入服务列表
  • changeDetection: 变更检测策略,缺省是检测所有组件
  • encapsulation: 使用Shadow DOM策略,缺省是ViewEncapsulation. Emulated

template和templateUrl两者使用其一,简单模板使用template即可。使用templateUrl会多一次HTTP请求,为改善性能使用Webpack时可采用以下方式: template: require(‘the_template.html’); Webpack能将HTML模板作为模块一起打包。 providers和viewProviders间有细微的差异,请参见4.5节说明。一般情况下,使用providers即可。

组件类的字段标注定义如下:

  • @Input: 定义属性绑定的输入字段
  • @Output: 定义事件绑定的输出字段用于触发事件
  • @HostBinding: 将宿主元素的属性绑定到组件类成员字段
  • @HostListener: 将组件类的成员函数注册到宿主元素的事件回调
  • @ContentChild:用于绑定内容中单个子组件,参见示例
  • @ContentChildren: 用于绑定内容中子组件列表
  • @ViewChild: 用于绑定模板中的单个子组件
  • @ViewChildren: 用于绑定模板中的子组件列表

组件分类

为了组件重用和逻辑清晰,可以将组件分为两类

  • 展示组件(Presentational Component):仅负责展现视图,一般没有应用状态
  • 容器组件(Container Component):包括应用状态,实现应用行为。 该方法好处是:
    • 更好地分离UI和逻辑
    • 展示组件重用性好
    • 设计师在界面上调整展示组件属性和组件功能无关
    • 迫使开发人员抽象出布局组件,而不是到处使用类似的布局代码。

模板语法 Template Syntax

模板语法用于定义组件模板,即@Component标注的template或templateUrl内容。

1. HTML

HTML元素可用于模板,script除外。一般地,html、body和base不会用于模板中。

2. 插值 Interpolation

插值使用{{和}}括起来,括号间内容叫做模板表达式(Template Expression)。插值计算为字符串加在HTML元素或者属性值中,例如:

<h3>
  {{ title }}
  <img src="{{ heroImageUrl }}"/>
</h3>

 

3. 模板表达式 Template Expression

模板表达式很像Javascript表达式,除了以下情况:

  • 不能是赋值,如=、+=等
  • 不能有new
  • 不能用;或,连接多个表达式
  • 不能是++、--
  • 不能是位操作&、|
  • 不能是表达式算符|、?.

模板表达式只能引用组件实例的成员,不能引用全局变量,包括window、document等。 编写模板表示式需注意以下问题:

  • 没有可视的副作用:即表达式不能修改其他属性的状态,从而改变其他界面显示
  • 执行很快:模板表达式可能在每次鼠标移动时被调用
  • 简单:复杂的业务逻辑应该实现在组件中,而不是写成模板表达式
  • 等幂性:即依赖值不变的话,模板表达式结果总是相同的。该特性该改进Angular变更检测的效率。

4. 模板语句 Template Statement

模板语句用于响应HTML元素、组件或Directive事件,语法如(event)=”statement”。

模板语句有类似模板表达式的语法限制。只能引用组件实例的成员,以及:

  • 模板局部变量,如#item
  • $event事件对象。

5. 绑定语法

数据绑定(Data Binding)是数据和视图自动保持一致的机制。

数据绑定按绑定方向分为以下三类:

  • 数据 -> 视图:{{expression}}或[target] = "expression",绑定类型包括Interpolation、Property、Attribute
  • 视图 -> 数据: (target) = "statement",绑定类型是Event
  • 双向绑定: [(target)] = "expression",一般用于表单

Attribute和Property的区别是:Attribute指HTML Attribute,由HTML规范定义;Property指DOM Property, 由Document Obejct Model定义。一般地,Attribute值用于初始化Property值,Attribute值是不变的,Property值在被初始化后可以改变。

Attribute和Property间没有必然联系,例如:

  • id既是Attribute又是Property
  • colspan是Attribute,但没有对应的Property
  • textContent是Property,但没有对应的Attribute。 注意,Angular 2数据绑定应用于Property和事件,而不是Attribute。

数据绑定按绑定类型分类如下:

  • Property
    • 元素Property,如<img [src] = "heroImageUrl">
    • 组件Property,如<hero-detail [hero]="currentHero"></hero-detail>
    • Directive Property,如<div [ngClass] = "{selected: isSelected}"></div>
  • Event
    • 元素事件,如<button (click) = "onSave()">Save</button>
    • 组件事件,如<hero-detail (deleteRequest)="deleteHero()"></hero-detail>
    • Directive事件,如<input [(ngModel)]="heroName">
  • 双向:
    • 事件和Property,如<input [(ngModel)]="heroName">
  • Attribute:
    • 元素 Attribute,如<button [attr.aria-label]="help">help</button>
  • Class:
    • 元素clsss Property,如<div [class.special]="isSpecial">Special</div>
  • Style:
    • 元素sytle Property,如<button [style.color] = "isSpecial ? 'red' : 'green'">

需要说明的是:

  • Property绑定固定不变字符串时,[]可省略,如<hero-detail prefix="You are my" [hero]="currentHero"></hero-detail>
  • 插值和数据绑定均可以用于模板时,推荐使用插值
  • 可以使用[class]绑定整个class
  • 可以使用ngClass和ngStyle Directive同时设置多个class或style
  • 可用于事件绑定的元素事件列表参见MDN
  • 事件参数命名为$event,对于DOM元素该对象是标准的DOM event对象
  • 双向绑定一般用于表单,相当于:
<input
  [ngModel]=" heroName "
  (ngModelChange)=" heroName =$event">

 

6. Built-in Directives

内置Directives包括:

  • ngFor: 循环显示模板
  • NgForTrackBy: 优化ngFor性能
  • ngIf: 根据if条件确定是否包括模板,false则不生成DOM
  • ngSwitch: 根据取值显示不同的模板
  • ngClass: 设置多个class属性
  • ngStyle: 设置多个style属性

ngFor、ngIf和ngSwtich的完整语法使用template元素,以ngIf说明如下:

<template  [ngIf]="currentHero">
  <hero-detail [hero]="currentHero"></hero-detail>
</template>

 

简单起见可使用*ngIf如下:

<hero-detail *ngIf="currentHero" [hero]="currentHero"></hero-detail>

 

7. 模板局部变量

使用#定义模板局部变量,以便在模板中引用该变量。例如:

<input  #phone>
<button (click)="callPhone(phone.value)">Call</button>

 

一般地,ngFor总会使用到模板局部变量。例如:

<li *ngFor="#n of names">
  姓名是{{n}}
</li>

 

注意,Angular 2 beta 17语法已改为:

<li *ngFor="let n of names">
  姓名是{{n}}
</li>

 

8. 模板表达式算符

  • Pipe:格式转换,如<div>{{ title | uppercase }}</div>
  • Elvis: 能处理null或undefined,如The name is {{hero?.firstName}}
posted @ 2016-05-02 20:38  weisp  阅读(340)  评论(0编辑  收藏  举报