针对RC.5更新
使用Angular 2,我们可以
debounceTime()在窗体控件的
valueChanges可观察对象上使用RxJS运算符进行反跳:
import {Component} from '@angular/core';import {FormControl} from '@angular/forms';import {Observable} from 'rxjs/Observable';import 'rxjs/add/operator/debounceTime';import 'rxjs/add/operator/throttleTime';import 'rxjs/add/observable/fromEvent';@Component({ selector: 'my-app', template: `<input type=text [value]="firstName" [formControl]="firstNameControl"> <br>{{firstName}}`})export class AppComponent { firstName = 'Name'; firstNameControl = new FormControl(); formCtrlSub: Subscription; resizeSub: Subscription; ngonInit() { // debounce keystroke events this.formCtrlSub = this.firstNameControl.valueChanges .debounceTime(1000) .subscribe(newValue => this.firstName = newValue); // throttle resize events this.resizeSub = Observable.fromEvent(window, 'resize') .throttleTime(200) .subscribe(e => { console.log('resize event', e); this.firstName += '*'; // change something to show it worked }); } ngDoCheck() { console.log('change detection'); } ngonDestroy() { this.formCtrlSub.unsubscribe(); this.resizeSub .unsubscribe(); }}[Plunker](http://plnkr.co/edit/A8Ms99r7sazUeZS90z7K?p=preview)
上面的代码还包括一个如何限制窗口调整大小事件的示例,如@albanx在下面的注释中所要求的。
尽管上面的代码可能是这样做的Angular方式,但效率不高。每个击键和每个调整大小事件(即使它们被去抖和抑制)都将导致更改检测运行。换句话说,
去抖动和节流不影响更改检测运行的频率。(我找到了TobiasBosch的GitHub评论,对此进行了确认。)您可以在运行插入器时看到此消息,并
ngDoCheck()在键入输入框或调整窗口大小时看到被调用了多少次。(使用蓝色的“
x”按钮在单独的窗口中运行导航按钮,以查看调整大小事件。)
一种更有效的技术是根据事件本身在Angular的“区域”之外创建RxJS
Observables。这样,每次事件触发时都不会调用更改检测。然后,在您的订阅回调方法中,手动触发更改检测-即,您控制何时调用更改检测:
import {Component, NgZone, ChangeDetectorRef, ApplicationRef, ViewChild, ElementRef} from '@angular/core';import {Observable} from 'rxjs/Observable';import 'rxjs/add/operator/debounceTime';import 'rxjs/add/operator/throttleTime';import 'rxjs/add/observable/fromEvent';@Component({ selector: 'my-app', template: `<input #input type=text [value]="firstName"> <br>{{firstName}}`})export class AppComponent { firstName = 'Name'; keyupSub: Subscription; resizeSub: Subscription; @ViewChild('input') inputElRef: ElementRef; constructor(private ngzone: NgZone, private cdref: ChangeDetectorRef, private appref: ApplicationRef) {} ngAfterViewInit() { this.ngzone.runOutsideAngular( () => { this.keyupSub = Observable.fromEvent(this.inputElRef.nativeElement, 'keyup') .debounceTime(1000) .subscribe(keyboardEvent => { this.firstName = keyboardEvent.target.value; this.cdref.detectChanges(); }); this.resizeSub = Observable.fromEvent(window, 'resize') .throttleTime(200) .subscribe(e => { console.log('resize event', e); this.firstName += '*'; // change something to show it worked this.cdref.detectChanges(); }); }); } ngDoCheck() { console.log('cd'); } ngonDestroy() { this.keyupSub .unsubscribe(); this.resizeSub.unsubscribe(); }}[Plunker](http://plnkr.co/edit/E77SzTXvBnaBL4SzyOgh?p=preview)
我使用
ngAfterViewInit()而不是
ngonInit()确保
inputElRef已定义。
detectChanges()将对此组件及其子组件运行更改检测。如果您希望从根组件运行更改检测(即运行完整的更改检测检查),请
ApplicationRef.tick()改用。(我
ApplicationRef.tick()在插件的注释中打了个电话。)请注意,
tick()将导致
ngDoCheck()被调用。



