数据绑定总体而言有三种类型:
- {{…}} 插值表达式绑定
- 属性绑定
- 事件绑定
插值表达式绑定
插值表达式绑定比较常见
// app.component.html
<h1>Hello {{title}}</h1>
// app.component.ts
...
export class AppComponent {
title = 'app';
}
属性绑定
<img src="{{src}}" /> 这种方式为传统的赋值,采用插值表达式
<img [src]="src" /> 使用[属性]="值"进行属性绑定才是angular中的属性绑定
事件绑定
<input (input)="onInputEvent($event)">
这里,小括号表示这是一个事件绑定
事件名称:input
组件方法:onInputEvent
浏览器事件对象:$event
当事件发生时执行的表达式:onInputEvent($event)
接下来看看 DOM绑定 与 HTML属性绑定 的关系:
DOM绑定与HTML属性绑定的区别
| DOM绑定 | HTML绑定 | |
|---|---|---|
| 相同情况下 | 一个元素的id | |
| 有HTML属性无DOM属性 | 表格中td的colspan | |
| 有DOM属性无HTML属性 | textContent属性 | |
| 关于值 | DOM表示当前值 | HTML表示初始值 |
| 关于可变 | DOM值是可变的 | HTML值是不可变的 |
结论:模板绑定 是通过 DOM属性 和 事件 来工作的,而不是 HTML属性。
<!--Dom属性绑定-->
<input value="Yan" (input)="doOnInput($event)">
上面已经提到,colspan 没有对应的DOM属性,只能使用 HTML属性 绑定:
<!--html属性绑定-->
<table border="solid">
<tr>
<!-- 以下表达式会报错:colspan不是td的属性
<td [colspan]="colspanSize">hello</td>
-->
<td [attr.colspan]="colspanSize" align="center">hello</td>
</tr>
</table>
protected colspanSize: number = 2;
HTML属性(attribute)绑定
当元素没有属性(native property)可绑的时候,就必须使用 attribute 绑定,例如<td>元素没有 colspan 属性,但是插值表达式和属性绑定只能设置属性,不能设置 attribute,这时我们便需要使用到 attribute绑定 来替我们解决这个问题。
如果对DOM属性(property)和HTML属性(attribute)有所疑惑,可通过下面的文字先做一个区分梳理:
attribute 初始化 DOM property,然后它们的任务就完成了,property 的值可以改变;attribute 的值不能改变。
例如,当浏览器渲染 <input type="text" value="abc"> 时,它将创建相应DOM 节点,其 value property 被初始化为 “abc”。当用户在输入框中输入 “abcwwww” 时,DOM元素的 value property 变成了 “abcwwww”。但是这个 HTML value attribute 保持不变。如果我们读 input 元素的 attribute,就会发现确实没变: input.getAttribute('value') // 返回 “abc”。
所以,在Angular的世界中,attribute 唯一的作用是用来初始化元素和指令的状态。 当进行数据绑定时,只是在与元素和指令的 property 和 事件 打交道,而 attribute 就基本上靠边站了,只有比较特殊的情况才会用到它。
具体绑定格式如下:
<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
样式绑定
如果要同时替换多个style,使用ngStyle指令绑定到一个对象上是更好的选择
<!--单一样式绑定-->
<div [style.color]="isRed?'red':'green'">单一样式绑定</div>
<!--多个样式绑定-->
<div [ngStyle]="divStyles">多个样式绑定</div>
protected isRed = Math.random() < 0.5;
protected divStyles: any = {
color: 'red',
background: 'yellowgreen'
};
类绑定
// 替换型绑定:即当 badCurly 有值时class的值会被完全替换成一个badCurly.
<div class="bad curly special"
[class]="badCurly">Bad curly</div>
// 增减类绑定:绑定到特定的类名
<div [class.special]="isSpecial">The class binding is special</div>
<!--单一类的控制-->
<div class="a b" [class.c]="isBig">判定是否有c类:{{isBig}}</div>
<!--多个类的控制-->
<div [ngClass]="divClasses">是否有类a:{{divClasses.a}}、b:{{divClasses.b}}和c:{{divClasses.c}}</div>
<!--以下两种方式效果相同,均为divClass的值'fontRedClass'-->
<div [class]="divClass">红色字体</div>
<div class="{{divClass}}">红色字体</div>
如果要同时替换多个class,使用ngClass指令绑定到一个对象上是更好的选择
<div [ngClass]="currentClasses">xxxx</div>
数据流向
分为 单向绑定 和 双向绑定
单向绑定
它的意思是要么是ts文件为html文件赋值,要么相反。
ts -> html
<div>
<img src="{{imgUrl}}">
<img [src]="imgUrl">
</div>
html -> ts
<input (keyup)="press($event)">
小结:ts -> html使用插值表达式 {{value}} 或 [attr] ,html->ts使用 (event)。ts -> html较为常用。
使用[]表示数据是从模型到模板的单项绑定
使用()表示数据是从模板到模型的单项绑定
双向绑定
ts文件与html文件中绑定的值同时改变。(另一种方法是 引用)
下列代码表示当HTML文件输入框内容改变时,ts文件的属性name的值同时改变。
<input [(ngModel)]="name">
它的作用等于:
html
<input [value]="name" (input)="doOnInput($event)">
ts
doOnInput(event: any) {
this.name = event.target.value;
}
注意:使用双向绑定时,必须导入 FormsModule:
// app/app.module.ts
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [...],
imports: [
...
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
当你要监听 ngModel 时,可以这样:
<input [(ngModel)]="tel" (ngModelChange)="modelChagne($event.target.value)">
<p>{{tel}}</p>
事实上,
我们可以把 ngModel 绑定 拆分成两个独立的绑定:属性绑定 和 事件绑定。
eg:ngModel 绑定
<input type="text" [(ngModel)]="name">
<div>{{ name }}</div>
改用 属性绑定 和 事件绑定
<input type="text" [ngModel]="username" (ngModelChange)="username = $event">
<div>{{ username }}</div>
(ngModelChange) 为事件绑定,看起来可能有点怪,来解释下:
因为 ngModelChange 并非 <input> 元素的事件。它实际来自 ngModel 指令的事件属性。
当 Angular 在表单中看到 [(x)] 的绑定目标时,它会期待这个 x 指令有一个名为 x 的输入属性,和一个名为 xChange 的输出属性。把这里的x替换成ngModel,就可以理解得通了。
还有一个可能会蒙圈的地方,是模板表达式中的 model.name = $event(在上例中为(ngModelChange)="username = $event")。我们理解的 $event对象 是来自DOM事件,但 ngModelChange属性 不会生成DOM事件,因为它是 Angular EventEmitter 类型的属性。
当它触发时,$event 返回的是输入框的值,也正是希望赋给组件name属性的值。
一开始的时候,[(ngModel)] 这种语法看起来可能有点奇怪。
我们知道 (eventName) 语法可以用来绑定组件所触发的事件(或者输入)。另外,我们还用 [propertyName] = “foobar” 这种语法来实现了单向数据绑定,把名为 propertyName 的属性设置为表达式 foobar 所执行的结果。
NgModel 语法只不过是把以上两种语法融合到一起从而实现双向数据绑定而已。这就是为什么我们认为它更像一种语法糖而不是一个新概念的原因。与 AngularJS 1.x 相比,这种语法最大的优点之一是:只要看一眼模板就能区别哪一种是单向绑定哪一种是双向绑定。
对比:引用 与 双向绑定
// login.component.html
<input #usernameRef type="text"> // #usernameRef 等价于 ref-usernameRef,即#名字等价于ref-名字
<input #passwordRef type="password">
<button (click)="onClick(usernameRef.value, passwordRef.value)">Login</button>
// login.component.ts
onClick(username, password) {
console.log('username:' + username + "\n\r" + "password:" + password);
}
// login.component.html
<input type="text"
[(ngModel)]="username"
/>
<input type="password"
[(ngModel)]="password"
/>
<button (click)="onClick()">Login</button>
// login.component.ts
username = "";
password = "";
onClick(username, password) {
console.log('username:' + this.username + "\n\r" + "password:" + this.password);
去掉参数的原因是双向绑定后,我们通过数据成员变量就可以知道用户名和密码了,不需要在传递参数了。而成员变量的引用方式是 this.成员变量 。
本文介绍了Angular4中的数据绑定,包括插值表达式绑定、属性绑定、事件绑定,详细阐述了DOM绑定与HTML属性绑定的区别,并讲解了样式绑定、类绑定、单向绑定和双向绑定的使用方法和数据流向。
484

被折叠的 条评论
为什么被折叠?



