【问题标题】:Angular click debounce角度点击去抖动
【发布时间】:2019-04-18 13:32:33
【问题描述】:

在我的模板中,我有一个字段和两个按钮:

<div class="btn-plus" (click)="add(1)"> - </div>
<div class="txt"> {{ myValue }} </div>
<div class="btn-minus" (click)="add(-1)"> + </div>

在我的组件 .ts 文件中,我有:

add(num) {
    this.myValue +=num;
    this.update(); // async function which will send PUT request
}

this.update() 函数将myValue 放入大 JSON 对象的适当字段中,并将其发送到服务器。

问题:当用户在加/减按钮上短时间点击 10 次时,会发送 10 次请求。但我只想发送一次请求 - 最后一次点击后 0.5 秒。 怎么做

【问题讨论】:

    标签: angular typescript rxjs debounce


    【解决方案1】:

    使用takeUntil 运算符:

    export class AppComponent  {
      name = 'Angular';
    
      calls = new Subject();
    
      service = {
        getData: () => of({ id: 1 }).pipe(delay(500)),
      };
    
      click() {
        this.calls.next(true);
        this.service.getData().pipe(
          takeUntil(this.calls),
        ).subscribe(res => console.log(res));
      }
    }
    

    Stackblitz(打开控制台查看日志)

    【讨论】:

    • 在 Stackblitz 中,每次单击“模拟 HTTP 调用”按钮时,我都会立即收到错误“错误类型错误:_co.simulate 不是函数”
    • 该死,我改名了——'再试一次!
    • 现在可以了。我给 +1(约 15 分钟前),但是这个解决方案不像 Cory Rylan 指令那样可重用,所以我不会“检查”它作为最佳答案。不过谢谢你的回答
    • 我不是来编写指令的,而是为您提供另一个线索,请随意创建指令!但我理解你的立场,我完全可以接受,尽管指令的使用比这复杂得多。
    • 你能解释一下你的解决方案吗?它有效,但我无法理解它,尽管我已经检查了文档并使用它。
    【解决方案2】:

    这是我在互联网上找到的部分答案,但我愿意接受更好的解决方案(或改进为以下解决方案(指令)):

    在互联网上我发现了appDebounceClick 指令,它可以通过以下方式帮助我:

    我从 .ts 文件中的 add 中删除了 update

    add(num) {
        this.myValue +=num;
    }
    

    并通过以下方式更改模板:

    <div 
        appDebounceClick 
        (debounceClick)="update()" 
        (click)="add(1)" 
        class="btn-plus"
        > - 
    </div>
    <div class="txt"> {{ myValue }} </div>
    <!-- similar for btn-minus -->
    

    奖金

    指令appDebounceClickCory Rylan 编写(我将代码放在这里以防链接将来停止工作):

    import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
    import { Subject } from 'rxjs/Subject';
    import { Subscription } from 'rxjs/Subscription';
    import { debounceTime } from 'rxjs/operators';
    
    @Directive({
      selector: '[appDebounceClick]'
    })
    export class DebounceClickDirective implements OnInit, OnDestroy {
      @Input() debounceTime = 500;
      @Output() debounceClick = new EventEmitter();
      private clicks = new Subject();
      private subscription: Subscription;
    
      constructor() { }
    
      ngOnInit() {
        this.subscription = this.clicks.pipe(
          debounceTime(this.debounceTime)
        ).subscribe(e => this.debounceClick.emit(e));
      }
    
      ngOnDestroy() {
        this.subscription.unsubscribe();
      }
    
      @HostListener('click', ['$event'])
      clickEvent(event) {
        event.preventDefault();
        event.stopPropagation();
        this.clicks.next(event);
      }
    }
    

    【讨论】:

      【解决方案3】:

      辅助函数 --

      export const debounced = (cb, time) => {
        const db = new Subject();
        const sub = db.pipe(debounceTime(time)).subscribe(cb);
        const func = v => db.next(v);
      
        func.unsubscribe = () => sub.unsubscribe();
      
        return func;
      };
      

      那么一个例子可以是:

      import { Component, OnInit } from '@angular/core';
      import { debounced } from 'src/helpers';
      
      @Component({
        selector: 'app-example',
        // Click calls `debouncedClick` instead of `myClick` directly
        template: '<button (click)="debouncedClick($event)">Click This</button>'
      })
      export class Example implements OnDestroy {
        debouncedClick; // Subject.next function
      
        constructor() {
          // Done in constructor or ngOnInit for `this` to resolve
          this.debouncedClick = debounced($event => this.myClick($event), 800);
        }
      
        // Called after debounced resolves (800ms from last call)
        myClick($event) {
          console.log($event);
        }
      
        ngOnDestroy() {
          // Stay clean!
          this.debouncedFunc.unsubscribe();
        }
      }
      

      还可以反转用法,在单击时调用“myClick”并让debounced 回调执行所需的操作。经销商的选择。

      我个人也是为了(keyup) 事件。

      不确定取消订阅是否真的有必要 - 实施起来比研究内存泄漏要快:)

      【讨论】:

        猜你喜欢
        • 2017-12-17
        • 2013-10-06
        • 2021-07-04
        • 1970-01-01
        • 2020-11-23
        • 1970-01-01
        • 2017-12-16
        • 2014-08-22
        • 2014-11-20
        相关资源
        最近更新 更多