Событие клика, созданное с помощью Rx Js, генерируется больше раз, чем собственное событие клика - PullRequest
1 голос
/ 26 мая 2020

Мне нужно различать guish короткие (<400 мс) и длинные (> 400 мс) клики. Я реализовал оба события с помощью Rx Js, но короткий щелчок излучает больше, чем должен, если пользователь начинает быстро щелкать элемент.

app.component. html

<button #button (click)="onBuiltInClickEvent()">Click</button>
<p>Method was called: {{ calledTimes }}</p>
<p>Native click was called: {{ nativeClick }}</p>

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewInit {
  @ViewChild("button")
  public button: ElementRef;

  public calledTimes: number = 0;
  public nativeClick: number = 0;

  private mouseDown$: Observable<MouseEvent>;
  private mouseUp$: Observable<MouseEvent>;
  private click$: Observable<MouseEvent>;

  public ngAfterViewInit(): void {
    this.mouseDown$ = fromEvent(this.button.nativeElement, "mousedown");
    this.mouseUp$ = fromEvent(this.button.nativeElement, "mouseup");

    this.click$ = this.mouseDown$.pipe(
        flatMap(_ => {
            return this.mouseUp$.pipe(timeoutWith(400, EMPTY));
        })
    );

    this.click$.subscribe(_ => this.onClick());
  }

  private onClick(): void {
    this.calledTimes++;
  }

  public onBuiltInClickEvent(): void {
    this.nativeClick++;
  }
}

enter image description here

Рабочий stackblitz .

1 Ответ

1 голос
/ 26 мая 2020

flatMap не будет подходящим оператором карты в этом сценарии. Вы не хотите sh сглаживать (или объединять) внутреннее наблюдаемое. В этом сценарии одновременно должна быть активна только одна внутренняя подписка. Таким образом, вы можете использовать оператор switchMap.

Я также вижу, что вы не обрабатываете ошибку из-за тайм-аута или повторно подписываетесь на наблюдаемый объект, если он истекает. Для этого вы можете использовать оператор Rx JS retryWhen. Попробуйте следующее

this.click$ = this.mouseDown$.pipe(
  switchMap(_ => this.mouseUp$.pipe(
    timeout(400),
    retryWhen(e => of('timeout error'))
  ))
);

Я изменил ваш Stackblitz

...