在 AngularJS 中,我能够通过使用 ng-model 选项来去除模型的抖动。
ng-model-options="{ debounce: 1000 }"
如何在 Angular 中对模型进行去抖动处理?
我试图在文档中搜索 debounce,但找不到任何内容。
https://angular.io/search/#stq=debounce&stp=1
一个解决方案是编写我自己的去抖功能,例如:
import {Component, Template, bootstrap} from 'angular2/angular2';
// Annotation section
@Component({
selector: 'my-app'
})
@Template({
url: 'app.html'
})
// Component controller
class MyAppComponent {
constructor() {
this.firstName = 'Name';
}
changed($event, el){
console.log("changes", this.name, el.value);
this.name = el.value;
}
firstNameChanged($event, first){
if (this.timeoutId) window.clearTimeout(this.timeoutID);
this.timeoutID = window.setTimeout(() => {
this.firstName = first.value;
}, 250)
}
}
bootstrap(MyAppComponent);
还有我的html
<input type=text [value]="firstName" #first (keyup)="firstNameChanged($event, first)">
但我正在寻找内置函数,Angular 中有吗?
最佳答案
针对 RC.5 更新
在 Angular 2 中,我们可以在表单控件的 valueChanges
可观察对象上使用 RxJS 运算符 debounceTime()
去抖动:
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();
}
}
上面的代码还包含一个如何限制窗口大小调整事件的示例,正如@albanx 在下面的评论中所询问的那样。
虽然上面的代码可能是 Angular 的方式,但效率不高。每一次击键和每一次调整大小事件,即使它们被去抖动和限制,都会导致变化检测运行。换句话说,去抖动和节流不会影响更改检测的运行频率。 (我发现 Tobias Bosch 的 GitHub comment 证实了这一点。)您可以在运行 plunker 时看到这一点,并且可以看到当您在输入框中键入时 ngDoCheck()
被调用了多少次或调整窗口大小。 (使用蓝色的“x”按钮在单独的窗口中运行 plunker 以查看调整大小事件。)
一种更有效的技术是在 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();
}
}
我使用 ngAfterViewInit()
而不是 ngOnInit()
来确保定义了 inputElRef
。
detectChanges()
将对此组件及其子组件运行更改检测。如果您更愿意从根组件运行更改检测(即运行完整的更改检测检查),则使用 ApplicationRef.tick()
反而。 (我在 plunker 的注释中调用了 ApplicationRef.tick()
。)请注意,调用 tick()
将导致 ngDoCheck()
被调用。
关于javascript - Angular 2+ 和去抖动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32051273/