当前位置: 首页 > 面试题库 >

角度和去抖动

姚自强
2023-03-14
问题内容

在AngularJS中,我可以通过使用ng-model选项来反跳模型。

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

如何在Angular中对模型进行反跳?我试图在文档中搜索反跳,但找不到任何东西。

一种解决方案是编写我自己的防抖动功​​能,例如:

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,我们可以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()被调用。



 类似资料:
  • 在AngularJS中,我能够使用ng-model选项来防抖模型。 如何在Angular中给模型去抖?< br >我试图在文档中搜索去抖,但什么也找不到。 https://angular.io/search/#stq=debounce 解决方案是编写自己的去抖动函数,例如: 和我的网页 但我正在寻找内置功能,Angular中有吗?

  • 问题 你想只执行某个函数一次,在开始或结束时把多个连续的调用合并成一个简单的操作。 解决方案 使用一个命名函数: debounce: (func, threshold, execAsap) -> timeout = null (args...) -> obj = this delayed = -> func.apply(obj, args) unless exe

  • 问题内容: 对于我正在编写的某些代码,我可以使用Java中的一个不错的通用实现。 当被称为多次毫秒具有相同参数的回调函数应调用一次。 可视化: (某种程度上)这已经在某些Java标准库中存在了吗? 您将如何实施? 问题答案: 请考虑以下线程安全解决方案。请注意,锁定粒度是在密钥级别上的,因此仅同一密钥上的调用会相互阻塞。它还处理在调用call(K)时发生的密钥K过期的情况。

  • 这是我现在的效果,拖动时会抖动,并且点击图例后都会执行一次这个动画: 下面复现代码的gif图: echarts 编辑器 如何给这个动画去抖呢? 其次: 有更好的动画效果推荐吗? 点击图例后都会执行一次这个动画,这个怎么修改呢?

  • 在我的模板中,我有一个字段和两个按钮: 在我的组件. ts文件中,我有: 这个。update()函数将myValue放入大JSON对象的适当字段中,并将其发送到服务器。 问题:当用户在短时间内点击10次加号/减号按钮时,将发送10次请求。但我只想发送一次请求-在上次单击后0.5秒。怎么做?

  • 本文向大家介绍angular.js和vue.js中实现函数去抖示例(debounce),包括了angular.js和vue.js中实现函数去抖示例(debounce)的使用技巧和注意事项,需要的朋友参考一下 问题描述 搜索输入框中,只当用户停止输入后,才进行后续的操作,比如发起Http请求等。 学过电子电路的同学应该知道按键防抖。原理是一样的:就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒