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

问题描述 投票:0回答:1

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

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个Subjects然后使用switchMap取决于你是暂停还是继续,但就像我说我无法弄清楚究竟是多少。

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

有什么指针吗?

rxjs rxjs6
1个回答
1
投票

检查this stackblitz interactivethis static viz example

主要技巧是至少等待

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

并让鼠标输入和输出添加到延迟。

concatMap内部的魔力确实如此(至少,我认为它确实...)

首先,我们将notifications$和concatMap延迟。因此,每个msg至少会显示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)
  })

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

© www.soinside.com 2019 - 2024. All rights reserved.