鼠标悬停时暂停通知流,鼠标悬停时恢复通知

时间:2019-02-25 08:44:30

标签: rxjs rxjs6

我有显示/隐藏通知的流:

this.subscription = this.notificationsApi.notifications$.pipe(
  concatMap((event) => {

    return of(event).pipe(
      delay(450),
      tap(() => {
        this.notification = event;
        this.isActive = true;
        this.cd.markForCheck();
      }),
      delay(isDefined(event.showFor) ? event.showFor : this.hideAfter),
      /// Pause here if you hover over the notification ///
      tap(() => {
        this.isActive = false;
        this.cd.markForCheck();
      }),
      delay(450)
    );
  })
).subscribe(() => {});

我想做的是当您将鼠标悬停在通知上方时暂停流,而当您不再将鼠标悬停在通知上方时继续操作:

<div (mouseover)="pause()" (mouseout)="continue()"></div>

在这里,我似乎找不到在这种情况下可行的解决方案。我假设我必须再使用1-2个Subject,然后再使用switchMap,具体取决于您暂停还是继续,但是就像我说的那样,我不知道该怎么做。

我尝试查看this StackBlitz for switchMap pause/resume functionality,但是当我尝试这种方法时,它根本没有显示任何通知。

有指针吗?

1 个答案:

答案 0 :(得分:1)

检查 this stackblitz interactivethis static viz example

主要技巧是至少等待

  • 通知显示延迟
  • 以及信息流中的下一条消息

并让鼠标来回增加延迟。

concatMap内的魔力可以做到这一点(至少,我认为它可以...)

开始,我们使用notifications$并对其延迟concatMap。因此,每个味精将至少显示DELAY

注意:伪代码

notifications$.concatMap(msg => 
  timer(DELAY)
    .ignoreElements()
    .startWith(msg)
)

然后,我们希望鼠标延迟延迟时间

notifications$
  .concatMap(msg =>
    mouse$
      .switchMap(isOver => { // < We re-delay on mouse state change
        if (isOver) {
          return empty() // < Do nothing when user hovers
        }

        return timer(DELAY); // < after DELAY -- take in next msgs
      })
      // we need only one completion event from this mouse$+ stream
      .take(1)
      // existing logic to turn delay stream into msg stream with delay
      .ignoreElements()
      .startWith(msg)
  )

最后,如果在DELAY之后出现下一条消息-我们仍需要收听鼠标悬停并延迟它们的移动

// store current msg index
let currentMsgIndex = -1;

notifications$

  // store current msg index
  .map((msg,i) => {
    currentMsgIndex = i;
    return msg;
  })

  .concatMap((msg, i) => {
    // we listen to events from the mouse
    return memMouse$
      // if mouse pos changed -- reeval timeout
      .switchMap(value => {

        // do nothing on mouse in
        if (value) {
          return empty();
        }

        // until next msg comes in -- we're tracking mouse in/out
        let nextMsgAwait$;
        if (i == currentMsgIndex) {
          // current msg is latest
          nextMsgAwait$ = notifications$.pipe(take(1));
        } else {
          // we already have next msgs to show
          nextMsgAwait$ = of(void 0);
        }

        // if mouse is away -- wait for
        // - timer for TIMEOUT
        // - and till new msg arrives

        // until then -- user can mouse in/out
        // to delay the next msg display

        return forkJoin(
          timer(TIMEOUT)
          , nextMsgAwait$
        );

      }),
      // we need only one completion event from this mouse$+ stream
      .take(1)
      // existing logic to turn delay stream into msg stream with delay
      .ignoreElements()
      .startWith(msg)
  })

为了更好地理解,请参见上面提到的示例-我在其中添加了一些评论。