【问题标题】:RxJS mouse activity trackingRxJS 鼠标活动跟踪
【发布时间】:2018-06-04 06:21:57
【问题描述】:

我正在开发用户活动跟踪系统并尝试实现下一个目标:

  1. 在用户开始移动鼠标两秒后捕获一次 mousemove 事件。
  2. 在用户完成鼠标移动两秒后捕捉片刻。

我有下一个流:

const activityStream$ = Rx.Observable.fromEvent(document, 'mousemove');

const enterActivityStream$ = activityStream$.throttleTime(1000).skip(2);

const finishActivityStream$ = activityStream$.debounceTime(2000);

它们分别按预期工作,我想将它们组合起来,因此它们将以重复的方式工作。

例如: 用户开始移动鼠标,两秒钟后观察者收到有关该事件的事件(或至少do 运算符),然后用户完成移动鼠标并且观察者也收到有关该事件的通知。如果用户再次开始移动鼠标,则重复此例程。

我在Example RxJS Observable when mouse or click activity Re-starts 发现了类似的问题,但解决方案似乎很复杂并且无法按预期工作。 (lastact$ 流会触发两次,而应该触发一次)。

请问,谁能告诉我如何实现这一目标?谢谢!

【问题讨论】:

    标签: rxjs rxjs5


    【解决方案1】:

    我认为你可以只使用merge:

    Observable.merge(
        enterActivityStream$, 
        activityStream$, 
        finishActivityStream$,
      )
      .subscribe(...)
    

    根据您的描述,您似乎只想在 2s 间隔后开始发出任何值,因此您也可以这样做:

    enterActivityStream$
      .take(1)
      .mergeMap(() => activityStream$)
      .takeUntil(finishActivityStream$)
      .repeat()
      .subscribe(...);
    

    【讨论】:

    • 感谢您的回复,马丁。这两种情况的问题是skip(2) 只在第一次生效。如果我重复此例程,skip(2) 将不再起作用,因此enterActivityStream$ 立即开始调度(很公平,已经跳过了 2 个第一个事件)。我需要以某种方式重新启动enterActivityStream$ 或整个序列。这样的事情可能吗?
    • skip(2)throttleTime 之后应该在那里做什么?看起来您可以使用.throttleTime(2000),当您在描述中提到“用户开始移动鼠标两秒后捕获一次鼠标移动事件。”
    • skip(2) 应该在前 2 秒内跳过鼠标移动。想象一下,如果用户不小心触摸了鼠标。我不想跟踪此类活动。这就是为什么我只想在鼠标移动两秒钟后开始跟踪。如果我这样做throttleTime(2000) 意外触摸无论如何都会过去。这是不受欢迎的行为。我觉得解决方案一定很容易,但我不知道如何处理它。对我来说,似乎我需要适当过滤鼠标移动,但我不知道该怎么做。
    • 查看我的更新。所以enterActivityStream$ 只有一个发射,然后它一直从activityStream$ 发射直到.takeUntil(finishActivityStream$)。完成后,它会使用repeat() 重复整个过程
    • 看起来真的很接近。现在唯一的问题是我无法将finishActivityStream$ 发送到subscribe。你能看看这个jsbin example吗?我可以在其中包含finishActivityStream$ 吗?
    【解决方案2】:

    感谢Martin。最后我能够达到所需的解决方案。它有效,但我将不胜感激任何改进此代码的建议。

    const activityStream$ = Rx.Observable.fromEvent(document, 'mousemove').mapTo(true);
    
    const enterActivityStream$ = activityStream$
      .throttleTime(2000)
      .skip(1) // Skip first event to avoid accidental touches
      .takeUntil(activityStream$.debounceTime(100)) // reset after 100 milliseconds of inactivity
      .repeat(); // and then repeat
    
    const finishActivityStream$ = activityStream$.debounceTime(2000).mapTo(false);
    
    
    enterActivityStream$
      .mergeMap(() => activityStream$.merge(finishActivityStream$)) 
      .distinctUntilChanged()
      .take(2) // Take true (activity started) and then false (activity stopped).
      .repeat() // And then repeat
      .subscribe(active => {
        if (active) {
          console.log('Notify about activity being started');
        } else {
          console.log('Notify about activity being stopped');
        }
      })
    

    【讨论】:

      【解决方案3】:

      如果您还在寻找,请在stackblitz 上查看此解决方案

      import { interval, fromEvent } from 'rxjs';
      import { throttle, tap, debounceTime, delay } from 'rxjs/operators';
      
      const source = fromEvent(document, 'mousemove');
      
      const untilIsActiv = source.pipe(
        debounceTime(2000),
        tap(val => console.log(`caugth inactivity`))
      );
      
      const example = source
        .pipe(
          delay(2000),
          throttle(val => untilIsActiv)
        );
      
      
      const subscribe = example.subscribe(val => console.log('caugth event'));
      

      【讨论】:

        猜你喜欢
        • 2022-06-22
        • 2022-11-10
        • 1970-01-01
        • 2013-08-21
        • 2011-07-24
        • 2019-09-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多