RxJS-检测长时间按下鼠标

时间:2018-07-22 19:02:39

标签: javascript rxjs reactive

我想检测mousedown何时被发射超过500毫秒,如果是的话-做点什么。我的尝试:

const button = document.querySelector('button')
const stream = Rx.Observable.fromEvent(button, 'mousedown')
const mouseUp$ = Rx.Observable.fromEvent(button, 'mouseup')
stream.delay(500).takeUntil(mouseUp$).subscribe(() => console.log(1))

它有效,但仅在第一次运行时可用。然后,由于takeUntil运算符而取消了该流。如何使其每次都能工作?

DEMO

3 个答案:

答案 0 :(得分:3)

在每个express.static()事件中启动TimerObservable持续500毫秒。如果mouseDown$mouseUp$起的500毫秒内unsubscribe被发射。

TimerObservable

RxJS> = 6.0.0

const button = document.querySelector('button')
const mouseDown$ = Rx.Observable.fromEvent(button, 'mousedown')
const mouseUp$ = Rx.Observable.fromEvent(button, 'mouseup')

const stream$ = mouseDown$.switchMap(() => Rx.Observable.TimerObservable(500).takeUntil(mouseUp$));

stream$.subscribe(() => console.log('Only Fired after 500ms'))

答案 1 :(得分:1)

鼠标保持指令的示例:

@Directive({ selector: "[appMouseHold]" })
export class MouseHoldDirective implements OnInit, OnDestroy {
  @Input() set appMouseHold(tick: string | number) {
    if (typeof tick === 'string') {
      tick = parseInt(tick, 10);
    }
    
    this.tick = tick || 500;
  }
  private tick: number;
  private readonly _stop = new Subject<void>();
  private readonly _start = new Subject<void>();
  private subscription: Subscription;

  @Output() mousehold = new EventEmitter<number>();
  @Output() mouseholdstart = new EventEmitter<void>();
  @Output() mouseholdend = new EventEmitter<void>();

  ngOnInit() {
    this.subscription = this._start
      .pipe(
        tap(() => this.mouseholdstart.emit()),
        switchMap(() =>
          timer(500, this.tick).pipe(
            takeUntil(this._stop.pipe(tap(() => this.mouseholdend.emit())))
          )
        )
      )
      .subscribe((tick) => {
        this.mousehold.emit(tick);
      });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

  @HostListener("mousedown", ["$event"])
  onMouseDown($event) {
    if ($event.button === 0) {
      this._start.next();
    }
  }

  @HostListener("mouseup")
  onMouseUp() {
    this._stop.next();
  }
}

请参见Stackblitz

对于非角度使用,您可以简单地将@HostListener处理程序替换为fromEvent()可观察对象

答案 2 :(得分:0)

SplitterAlex's answer很好,但是takeUntil()完成了可观察的操作,您无法再处理事件,因此我的解决方法是(无法完成可观察的操作)

public touchStartSubject: Subject<any> = new Subject<any>();
public touchStartObservable: Observable<any> = this.touchStartSubject.asObservable();

public touchEndSubject: Subject<any> = new Subject<any>();
public touchEndObservable: Observable<any> = this.touchEndSubject.asObservable();

@HostListener('touchstart', ['$event'])
public touchStart($event: TouchEvent): void {
    this.touchStartSubject.next($event);
}

@HostListener('touchend', ['$event'])
public touchEnd(): void {
    this.touchEndSubject.next(null);
}

this.touchStartObservable
        .pipe(
            mergeMap((res) => race(
                timer(1500).pipe(map(() => res)),
                this.touchEndObservable,
            )),
        )
        .subscribe((res: TouchEvent) => {
             if (!res) return;
             // do stuff
        })

如果有人可以在没有if (!res) return;条件的情况下(例如,使用.error代替.next的{​​{1}}