HTML是Angular模板的语言。几乎所有的HTML语法都是有效的模板语法。
有些HTML元素在模板中没有什么意义,如<html>
、<body>
、<base>
。
我们可以使用组件和指令作为新的元素和属性来扩展HTML词汇。
插值绑定是单向数据绑定方式。可以在元素内或者元素的属性内绑定:
<p>My current hero is {{currentHero.firstName}}</p>
<h3>
{{title}}
<img src="{{heroImageUrl}}" style="height:30px">
</h3>
双括号内通常是组件属性的名称。事实上,双括号内是模板表达式(template expression),Angular会先计算它在转换成字符串。在Angular内部视线中,插值绑定会转换成属性绑定。
<!-- "The sum of 1 + 1 is 2" -->
<p>The sum of 1 + 1 is {{1 + 1}}</p>
模板表达式能计算出一个值。Angular执行表达式并将它分配到绑定目标的属性上,这个绑定目标可以是HTML元素、组件或指令。
我们将模板表达式放在插值绑定的双大括号内,就像{{1+1}}
;或者在属性绑定中等号右边的引号内,[property]="expression"
。
模板表达式看起来像是JavaScript表达式,但并不是所有的JavaScript表达式都是合法的模板表达式。具有副作用的JavaScript表达式是被禁止的,包括:
=
、+=
、-=
);
或者,
的链式表达式++
、--
)还有跟JavaScript表达式不一样的地方有:
|
、&
)|
、?
)模板表达式中不能访问全局命名空间,如window
和document
。表达式的上下文是组件实例。
当我们看到{{title}}
和[disabled]="isUnchanged"
,我们就知道title
和isUnchanged
是数据绑定组件的属性。
模板表达式还可以访问其它对象,例如本地模板变量(local template variable)。
!
这样的很简单的运算。模板声明对应绑定目标触发的事件,也就是事件绑定(event)="statement"
中等号右边引号内的部分。
模板声明有一个副作用,也就是Angular如何从用户输入更新应用状态的。
跟模板表达式相似,模板声明也是看起来像JavaScript表达式。与模板表达式不同的是,模板声明支持赋值运算符=
和使用;
和,
的链式表达式。它同样不支持以下几个:
++
、--
)、
-=`)|
、&
)|
、?
)跟模板表达式一样,模板声明也不能访问全局命名空间。
模板声明的上下文是绑定事件的组件实例。(click)="onSave()"
中的onSave
肯定就是绑定的组件实例的一个方法。
模板声明的上下文除了组件可能还有其他对象,如本地模板变量。
数据绑定分为三种:
从数据源到目标视图的单向数据绑定,绑定类型有Interpolation、Property、Attribute、Class、Style。
{{expression}}
[target] = "expression"
bind-target = "expression"
从目标视图数据源到数据源的单向数据绑定,绑定类型有Event。
(target) = "statement"
on-target = "statement"
双向数据绑定。绑定类型有Two-way。
[(target)] = "expression"
bindon-target = "expression"
除了插值绑定,其它绑定类型都有一个在等号左侧的目标名称,要么放在中括号或小括号内([]
、()
),要么就有个前缀(bind
、on
、bindon-`)。
看这个绑定:
<button [disabled]="isUnchanged">Save</button>
直觉告诉我们,这句代码的意思是将按钮的disabled
属性的当前值设置为组件的isUnchanged
属性值。然而并不是这样,当我们使用数据绑定时,我们使用的就不再是HTML属性了。我们不是在设置属性(attribute),而是设置DOM元素、组件和指令的属性(property)。
Attribute是针对HTML的,Propertiy是针对DOM的。
一些HTML attribute和DOM property是一一对应的,例如id
。一些HTML attribute没有对应的DOM property,例如colspan
。一些DOM property没有对应的HTML attribute,例如textContext
。
HTML attribute用于初始化DOM property,之后就没有它们什么事了。DOM property可以改变,而HTML attribute的值不回变。
例如,当浏览器渲染<input type="text" value="Hui">
,浏览器会创建一个相应的DOM节点,节点的value
属性的值初始化为"Tom"。当用户向文本框中输入"Jerry",DOM元素的value属性值为"Jerry",而HTML的value属性还是"Tom",使用input.getAttribute('value')
可以看到。
HTML attribute的值是指定初始值,DOM property的值是当前值。
disabled是个特例。一个按钮的disabled属性默认为false,按钮是启用的。当我们添加了disabled属性,它的disabled属性就被初始化为true,按钮被禁用。也就是说,通过添加或移除disabled属性来禁用或启用按钮。该属性的值是不可变的,因此我们不能通过isabled="false"
来启用按钮。
设置按钮的disabled property来禁用或启用按钮,只有property的值才能变化并起作用。
HTML attribute和DOM property不是同一个东西,即使它们的名称是一样的。
总之,模板绑定使用的是property和event,不是attribute。在Angular2中,attribute唯一的作用就是初始化元素和指令的状态。当我们绑定数据时,我们使用的是元素和指令的属性以及事件。
数据绑定的目标是DOM中的一些东西。根据绑定类型的不同分为以下几种:
Property绑定
<!--Element property-->
<img [src] = "heroImageUrl">
<!--Component property-->
<hero-detail [hero]="currentHero"></hero-detail>
<!--Directive property-->
<div [ngClass] = "{selected: isSelected}"></div>
Event绑定
<!--Element event-->
<button (click) = "onSave()">Save</button>
<!--Component event-->
<hero-detail (deleteRequest)="deleteHero()"></hero-detail>
<!--Directive event-->
<div (myClick)="clicked=$event">click me</div>
Two-way绑定
<!--Event and property-->
<input [(ngModel)]="heroName">
Attribute绑定
<!--Attribute (the exception)-->
<button [attr.aria-label]="help">help</button>
Class绑定
<!--class property-->
<div [class.special]="isSpecial">Special</div>
Style绑定
<!--style property-->
<button [style.color] = "isSpecial ? 'red' : 'green'">
参考资料
Angular官方文档