首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Debounce @HostListener事件

Debounce @HostListener事件
EN

Stack Overflow用户
提问于 2017-06-19 23:53:14
回答 3查看 15.3K关注 0票数 33

我在Angular2中实现了一个简单的无限滚动指令。我使用@HostListener('window:scroll')获取scroll事件并解析来自$target的数据。

问题是,对于每个滚动事件,都会再次检查所有内容,而不需要检查。

我查看了ionic infinite-scroll指令以获取灵感,但他们不使用@HostListener,我猜他们需要更细粒度的控制。

我在搜索https://github.com/angular/angular/issues/13248时遇到了这个问题,但找不到任何方法来做我想做的事情。

我想如果我创建一个可观察对象,订阅它并将下一个项目推到它上面,我就会达到我想要的行为,但我无法做到这一点。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-06-20 00:34:26

我会利用去抖动方法装饰器,如下所示:

代码语言:javascript
复制
export function debounce(delay: number = 300): MethodDecorator {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const timeoutKey = Symbol();

    const original = descriptor.value;

    descriptor.value = function (...args) {
      clearTimeout(this[timeoutKey]);
      this[timeoutKey] = setTimeout(() => original.apply(this, args), delay);
    };

    return descriptor;
  };
}

并按如下方式使用它:

代码语言:javascript
复制
@HostListener('window:scroll', ['$event'])  
@debounce() 
scroll(event) {
  ...
}
票数 67
EN

Stack Overflow用户

发布于 2019-03-01 04:34:58

我真的很喜欢@yurzui的解决方案,我更新了很多代码来使用它。但是,我认为它包含了一个错误。在原始代码中,每个类只有一个timeout,但实际上每个实例都需要一个。

从角度上讲,这意味着如果使用@debounce()的组件在容器中被多次实例化,每个实例化都将cancelTimeout前一个实例化,只有最后一个实例化才会触发。

我提出这个小小的变体来消除这个麻烦:

代码语言:javascript
复制
export function debounce(delay: number = 300): MethodDecorator {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {

    const original = descriptor.value;
    const key = `__timeout__${propertyKey}`;

    descriptor.value = function (...args) {
      clearTimeout(this[key]);
      this[key] = setTimeout(() => original.apply(this, args), delay);
    };

    return descriptor;
  };
}

当然,可以更复杂地消除合成__timeout__属性的歧义。

票数 12
EN

Stack Overflow用户

发布于 2021-05-15 17:01:53

可以结合使用fromEventthrottleTime运算符来实现这一点。

与使用@HostListener修饰事件处理程序不同,您可以使用fromEvent (例如,在ngOnInit方法中)从事件创建一个可观察对象,然后使用throttleTime限制事件的发出。

代码语言:javascript
复制
...
import {fromEvent, Subscription} from 'rxjs';
import {tap, throttleTime} from 'rxjs/operators';


export class MyComponent implements OnInit, OnDestroy { 

  private eventSub: Subscription;

  ngOnInit() {
    this.eventSub = fromEvent(window, 'scroll').pipe(
      throttleTime(300), // emits once, then ignores subsequent emissions for 300ms, repeat...
      tap(event => this.scroll(event))
    ).subscribe();
  }

  scroll(event) {
    ...
  }

  ngOnDestroy() {
    this.eventSub.unsubscribe(); // don't forget to unsubscribe
  }
}

使用RXJS的一个优点是,您可以将自定义调度器传递给throttleTime操作符,以实现不同的行为。例如,您可以通过动画帧速率来限制事件发射(例如,限制触摸事件的发射)。

代码语言:javascript
复制
import {animationFrameScheduler, ...} from 'rxjs';
...

this.eventSub = fromEvent(window, 'touchmove').pipe(
  throttleTime(0, animationFrameScheduler),
  tap(event => ...)
).subscribe();
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44634992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档