我有显示/隐藏通知的流:
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,但是当我尝试这种方法时,它根本没有显示任何通知。
有指针吗?
答案 0 :(得分:1)
检查 this stackblitz interactive和this 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)
})
为了更好地理解,请参见上面提到的示例-我在其中添加了一些评论。