我有这个显示/隐藏通知的流:
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
s然后使用switchMap
取决于你是暂停还是继续,但就像我说我无法弄清楚究竟是多少。
我试着看看this StackBlitz for switchMap pause/resume functionality但是当我尝试这种方法时它根本没有显示任何通知。
有什么指针吗?
检查this stackblitz interactive和this 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)
})
为了更好地理解,请参阅上面提到的示例 - 我在那里添加了一些评论。