角度和去抖动 [英] Angular and debounce

查看:102
本文介绍了角度和去抖动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在AngularJS中,我可以使用ng-model选项去抖模型。

In AngularJS I can debounce a model by using ng-model options.

ng-model-options="{ debounce: 1000 }"

如何在Angular中去抖模型?我试图在文档中搜索去抖但我找不到任何东西。

How can I debounce a model in Angular? I tried to search for debounce in the docs but I couldn't find anything.

https://angular.io/search/#stq=debounce&stp=1

A解决方案是编写我自己的去抖函数,例如:

A solution would be to write my own debounce function, for example:

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中有一个吗?

But I'm looking for a build in function, is there one in Angular?

推荐答案

更新RC.5

使用Angular 2我们可以在表单控件的 valueChanges observable上使用RxJS运算符 debounceTime()进行去抖动:

With Angular 2 we can debounce using RxJS operator debounceTime() on a form control's valueChanges observable:

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

上面的代码还包含一个示例如何限制窗口调整大小事件,如@albanx在下面的评论中所述。

The code above also includes an example of how to throttle window resize events, as asked by @albanx in a comment below.

虽然上面的代码很可能这样做的角度方式,效率不高。每次击键和每次调整大小事件,即使它们被去抖动和限制,也会导致变化检测运行。换句话说,去抖动和限制不会影响更改检测的运行频率。 (我发现Tobias Bosch的 GitHub评论证实了这一点。)你你可以在运行plunker时看到这个,你可以看到当你在输入框中输入或调整窗口大小时,会调用多少次 ngDoCheck()。 (使用蓝色的x按钮在单独的窗口中运行plunker以查看调整大小事件。)

Although the above code is probably the Angular-way of doing it, it is not efficient. Every keystroke and every resize event, even though they are debounced and throttled, results in change detection running. In other words, debouncing and throttling do not affect how often change detection runs. (I found a GitHub comment by Tobias Bosch that confirms this.) You can see this when you run the plunker and you see how many times ngDoCheck() is being called when you type into the input box or resize the window. (Use the blue "x" button to run the plunker in a separate window to see the resize events.)

更有效的技术是自己创建RxJS Observables事件,在Angular的区域之外。这样,每次事件触发时都不会调用更改检测。然后,在您的订阅回调方法中,手动触发更改检测–即,您可以控制何时调用更改检测:

A more efficient technique is to create RxJS Observables yourself from the events, outside of Angular's "zone". This way, change detection is not called each time an event fires. Then, in your subscribe callback methods, manually trigger change detection – i.e., you control when change detection is called:

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

我使用 ngAfterViewInit()而不是 ngOnInit(),以确保定义 inputElRef

I use ngAfterViewInit() instead of ngOnInit() to ensure that inputElRef is defined.

detectChanges() 将对此组件及其子组件运行更改检测。如果您希望从根组件运行更改检测(即,运行完整更改检测检查),请使用 ApplicationRef.tick() 。 (我在plunker的评论中调用了 ApplicationRef.tick()。)注意调用 tick()将导致 ngDoCheck()被调用。

detectChanges() will run change detection on this component and its children. If you would rather run change detection from the root component (i.e., run a full change detection check) then use ApplicationRef.tick() instead. (I put a call to ApplicationRef.tick() in comments in the plunker.) Note that calling tick() will cause ngDoCheck() to be called.

这篇关于角度和去抖动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆