标签:
在mvc/mvvm类框架出现之前,开发者通常需要手动更新html并维护html与数据之间的关系。随着mvc思想在前端社区的普及和发展,view层和model层的解耦和分离机制已经是各框架的标配了。
令人欣喜的是,angular2在现有各框架的理论基础上对数据绑定重新进行了抽象,在架构上进行了革新,很有借鉴意义。从本文起我们就将开始讨论angular2中的数据绑定。
angular2中有四种数据绑定:插入符(interpolation)、单向绑定(one-way binding)、事件绑定(event binding)和双向绑定(two-way binding)。今天我们先介绍前两种:插入符和单向绑定。
说到数据绑定就不得不提到模板层和数据。在angular1中,以scope属性的形式存在的数据会通过watch机制来和模板进行绑定。具体操作中,既可以手动调用scope上的$watch方法,也可以在模板层中使用相关的绑定指令或大括号绑定语法。然而,direcitve和scope的关系却错综复杂:directive既可以复用父级的scope,也可以拥有自己的scope;当它拥有自己的scope时,这个scope既可以和父级scope没有继承关系,也可以通过prototype链来继承父级scope上的属性……总之,这种盘根错节的数据关系使得angular1对于开发者并不那么友好。自然,简化数据关系和数据结构就成了Google在angular2开发中的重要任务之一。
在angular2中,component和数据有了清晰的对应关系:模板层中绑定的数据就是当前组件的实例属性,scope的概念消失了。
我们先通过一些简单的例子来帮助大家认识一下这种关系:
@Component({ // selector告知angular在哪里初始化AppComponent这个组件 selector: ‘hello-world‘, // AppComponent组件的具体模板 template: ` <h1 class="{{color}}">hello world, from {{name}}</h1> ` }) export class AppComponent { public name: string = ‘Ralph‘; };
我们在AppComponent类中添加了string类型的name属性,并赋值为"Ralph";相应地,为了使name属性能够在模板中被显示出来,我们在<h1>标签中增加了{{name}},这就是angular2模板的插入符语法。
插入符语法不仅能用到html标签的内容上,也可以用到属性上:
import {Component} from ‘@angular/core‘; @Component({ styles: [` .blue{ background: blue; } `], // selector告知angular在哪里初始化AppComponent这个组 selector: ‘hello-world‘, // AppComponent组件的具体模板 template: ` <h1 class="{{classNames}}">hello world, from {{name}}</h1> ` }) export class AppComponent { public name: string = ‘Ralph‘; public classNames: string = ‘blue‘; };
在上面的例子中,我们在Component装饰器上增加了styles属性,styles属性的值是一个字符串数组,编译后将作为当前组件的css;同时,我们还使用了es6中的反引号语法来包裹整块字符串,省去了拼接的麻烦。h1上的class属性和AppComponent上的classNames属性进行了绑定,classNames被赋值为了blue,正好适配了class中的.blue选择器。
在进行属性绑定时,我们也可以使用单向绑定的语法:
import {Component} from ‘@angular/core‘; @Component({ styles: [` .blue{ background: blue; } `], // selector告知angular在哪里初始化AppComponent这个组 selector: ‘hello-world‘, // AppComponent组件的具体模板 template: ` <h1 [class]="classNames">hello world, from {{name}}</h1> ` }) export class AppComponent { public name: string = ‘Ralph‘; public classNames: string = ‘blue‘; };
请注意class两端的括号[]不能省略,否则只会在初始值时赋值,而不会对变化进行监听。
单向绑定语法还有一种较少使用的形式,把中括号换为bind-前缀,功能和上例等价:
import {Component} from ‘@angular/core‘; @Component({ styles: [` .blue{ background: blue; } `], // selector告知angular在哪里初始化AppComponent这个组 selector: ‘hello-world‘, // AppComponent组件的具体模板 template: ` <h1 bind-class="classNames">hello world, from {{name}}</h1> ` }) export class AppComponent { public name: string = ‘Ralph‘; public classNames: string = ‘blue‘; };
除了引入组件属性并放弃scope外,angular2在框架思想上还有一个比较有价值的贡献:彻底区分dom node属性(property)和html标签属性(attribute)。
由于中文表述上property和attribute都翻译为“属性”,国内的开发者对于这两个截然不同的概念可能相对缺少关注;然而在国外,如何区分property和attribute是最高频出现的前端基础面试题之一。既然大家都知道他们不同,那博主为什么还说这是angular2的贡献呢?angular2之前的框架,在遇到property和attribute相关的问题时,都只是“头痛医头,脚痛医脚”,只解决具体问题而没有抽象到框架层面上去。以react为例,在文档的forms章节中(https://facebook.github.io/react/docs/forms.html),认为input控件的value property和value attribute之间的不同步是传统html的一种缺失(absent when writing traditional form HTML);而angular2的态度相对更宏观一些:property和attribute不是同一个概念,二者之间没有绝对的对应关系,它们可以同步,也可以不同步,一些property在attribute中找不到对应,也有一些attribute在property中找不到对应;但是要记住一点,angular2的绑定是针对dom node property的绑定,而非针对HTML标签attribute的绑定。
在这样的设计之上,对于value、disabled、checked等属性的处理就很清晰了;更为重要的是,它也为指令间、组件间的数据传递打下了良好的基础。
以checked属性的绑定为例:
import {Component} from ‘@angular/core‘; @Component({ // selector告知angular在哪里初始化AppComponent这个组件 selector: ‘hello-world‘, // AppComponent组件的具体模板 template: ` <h1 class="{{color}}">hello world</h1> checked属性绑定测试:<input type="checkbox" [checked]="checked" /><br /> <button (click)="onClick()">click me</button> ` }) export class AppComponent { public checked: boolean = false; public onClick() { this.checked = !this.checked; } };
上面的例子中出现了对click事件的监听,暂时不是本节的重点,大家可以先忽略细节。input[type="checkbox"]上的checked属性和AppComponent上的checked属性进行了绑定。AppComponent上的checked属性初始值为false,用户每次点击按钮时,onClick方法被触发,checked的值会相对于上一个值取反,从而实现选中/反选多选框的效果。
style和class是两个比较特殊的属性:style作为行内属性时,其值依然是键值对的组合;class经常需要对某一个值进行添加和删除,以完成toggle的操作。angular2对style和class的绑定有进一步的封装。
对style进行绑定:
import {Component} from ‘@angular/core‘; @Component({ // selector告知angular在哪里初始化AppComponent这个组件 selector: ‘hello-world‘, // AppComponent组件的具体模板 template: ` <h1 class="{{color}}">hello world</h1> <button (click)="onClick()" [style.background]="color">更改背景色</button> ` }) export class AppComponent { public color: string = ‘blue‘; public onClick() { this.color = this.color === ‘blue‘ ? ‘green‘ : ‘blue‘; } };
对class进行绑定:
import {Component} from ‘@angular/core‘; @Component({ styles: [` .selected{ background: blue; } `], // selector告知angular在哪里初始化AppComponent这个组件 selector: ‘hello-world‘, // AppComponent组件的具体模板 template: ` <h1 class="{{color}}">hello world</h1> <button (click)="onClick()" [class.selected]="open">更改背景色</button> ` }) export class AppComponent { public open: boolean = false; public onClick() { this.open = !this.open; } };
需要对style和class进行操作时,除了使用数据绑定以外,也可以使用相应的指令,稍后的章节中会有所涉及。
既然angular2的数据绑定通常是对dom node property的绑定,那么需要绑定一个不具有property对应项的attribute属性怎么操作呢?作为一个例外,angular2为此提供了attr.attribute-name的绑定方式,以绑定aria-label属性为例:
import {Component} from ‘@angular/core‘; @Component({ // selector告知angular在哪里初始化AppComponent这个组件 selector: ‘hello-world‘, // AppComponent组件的具体模板 template: ` <h1 class="{{color}}">hello world</h1> <button [attr.aria-label]="type">help</button> ` }) export class AppComponent { public type: string = ‘help‘; };
对angular2的插入符和单向绑定的介绍就先到这里,事件绑定、双向绑定将放到后续的章节中。
[Step-By-Step Angular2](2)数据绑定之插入符和单向绑定
标签:
原文地址:http://www.cnblogs.com/front-end-ralph/p/5579770.html