# 双向数据绑定
双向绑定语法实际上是**属性绑定**和**事件绑定**的语法糖。 Angular 将 SizerComponent 的绑定分解成这样:
~~~
<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
~~~
# 自定义双向绑定属性(示例):
~~~
import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core';
@Component({
selector: 'twoway',
template: `
<input [(ngModel)]="username">
<p>Hello {{username}}!</p>
`
})
export class TwoWayComponent implements OnInit {
constructor() { }
usernameValue: string;
@Output() usernameChange = new EventEmitter();
@Input()
get username() {
return this.usernameValue;
}
set username(val) {
this.usernameValue = val;
this.usernameChange.emit(this.usernameValue);
}
ngOnInit() {
}
}
~~~
# [ngModel 內部运行机制](http://oomusou.io/angular/ngmodel/)
~~~
<select id="TDDSelect" [ngModel]="selectedId" (ngModelChange)="selectedId = $event">
<option *ngFor="let cloud of clouds" [value]="cloud.id">{{ cloud.name }}</option>
</select>
<p>{{ selectedId }}</p>
~~~
这个属性绑定看起来很眼熟,但事件绑定看起来有点怪。
`ngModelChange`并不是 `<select>`元素的事件。 它实际上是来自`NgModel`指令的事件属性。
**当 Angular 在表单中看到`[(x)]`的绑定目标时, 它会期待这个`x`指令有一个名为`x`的输入属性,和一个名为`xChange`的输出属性。**
模板表达式中的另一个古怪之处是`selectedId = $event`。 之前看到的`$event`对象来自 DOM 事件。 但`ngModelChange`属性不会生成 DOM 事件 —— 它是Angular EventEmitter类型的属性,当它触发时, 它返回的是输入框的值 —— 也正是希望赋给`selectedId`属性的值。
现实中,几乎总是优先使用`[(ngModel)]`形式的双向绑定。 只有当需要在事件处理函数中做一些特别的事情(例如合并或限制按键频率)时,才会拆分出独立的事件处理函数
常用形式:
~~~
<select id="TDDSelect" [(ngModel)]="selectedId">
<option *ngFor="let cloud of clouds" [value]="cloud.id">{{ cloud.name }}</option>
</select>
<p>{{ selectedId }}</p>
~~~
![](https://box.kancloud.cn/bfcd52b22db182c4e9b2371b241e768c_292x542.png)
1. 在 HTML 修改触发 DOM 的 `change` event
2. `change` event 触发了 Angular 的 `ngModelChange` event
3. 将 $event 传给 `selectedId` field
4. `ControlValueAccessor` 將 `$event.target.value` 指定給 `selectedId` field
5. `selectedId` field 被修改,引发 interpolation binding 自动更新 HTML
> 步骤 4 就是将 `$event.target.value` 转成 field 的黑魔法所在
>
# 变化检测
由于js语言并没有属性变化通知的机制,所以angular也不知道谁发生了变化,在什么时候变了。Angular的变化机制是:
![](https://box.kancloud.cn/262971687584e8a646592783725a9c4c_668x269.png)
## 数据何时变化
主要入下集中情况可能改变数据:
用户输入操作,比如点击,提交等。
请求服务端数据。
定时事件,比如setTimeout,setInterval。
这几点有个共同点,就是他们都是异步的。也就是说,所有的异步操作是可能导致数据变化的根源因素。
## 如何通知变化
在Angularjs中是由代码$scope.$apply()或者$scope.$digest触发,而Angular2接入了ZoneJS,由它监听了Angular所有的异步事件。ZoneJS重写了所有的异步API(所谓的猴子补丁,MonkeyPatch)。ZoneJS会通知 Angular 可能有数据发生变化,需要检测更新。
## 变化检测原理 – 脏检查
所谓脏检查就是存储所有变量的值,每当可能有变量发生变化需要检查时,就将所有变量的旧值跟新值进行比较,不相等就说明检测到变化,需要更新对应的视图。
Angular的核心是组件化,组件的嵌套会使得最终形成一棵组件树。Angular的变化检测可以分组件进行,每个组件都有对应的变化检测器`ChangeDetector`。可想而知,这些变化检测器也会构成一棵树。
另外,Angular的数据流是自顶而下的,从父组件到子组件单向流动。单向数据流向保证了高效、可预测的变化检测,尽管检查了父组件之后,子组件可能会改变父组件的数据使得父组件需要再次被检查,这是不被推荐的数据处理方式。在开发模式下,Angular会进行二次检查,如果出现上述情况,二次检查就会报错:ExpressionChangedAfterItHasBeenCheckedError(关于这个问题的答案,可以在参考资料中找到)。而在生产环境中,脏检查只会执行一次。
# 参考
https://angular.cn/guide/template-syntax#two-way-binding--span-classsyntaxspan-
[Angular2双向绑定及变化检测](http://easywork.xin/2018/02/24/ng2-6/)
[TWO-WAY DATA BINDING IN ANGULAR](https://blog.thoughtram.io/angular/2016/10/13/two-way-data-binding-in-angular-2.html)
- PWA 概念
- Immutable
- Angular 基础概念
- 入门参考
- Angular 更新总结
- Angular 生态系统
- Rx.js
- Ngrx
- CQRS/ES 模式
- Angular 5 详解
- 测试
- 定义共享模块
- 懒路由加载
- angular组件
- 双向绑定及变化检测
- 样式
- ionic 3详解
- ionic3
- ionic 插件
- Ionic 添加动画
- Ghost-Loading
- 打包发布
- Android上架国内应用市场流程
- 总结
- 文章
- 问题合集
- Cordova
- 插件开发指南
- Android插件开发指南-官网
- IOS插件开发指南-官网
- Hooks 编写
- 桥接技术
- ===cordova插件收集===
- 相关主题-官网
- 实战-自定义插件流程
- UI 及 相关资源