💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 双向数据绑定 双向绑定语法实际上是**属性绑定**和**事件绑定**的语法糖。 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)