在鼠标悬停时暂停通知流并在鼠标移开时恢复
Pause notifications stream on mouseover and resume on mouseout
我有这个流 shows/hides 通知:
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 and this static viz example
主要技巧是至少等待
- 通知显示延迟
- 和流中的下一条消息
并让鼠标来回移动以增加延迟。
concatMap
内部的魔法可以做到这一点(至少,我认为是这样......)
开始,我们把notifications$
和concatMap延迟一下就可以了。因此,每条消息至少会显示 DELAY
次
注意:伪代码
notifications$.concatMap(msg =>
timer(DELAY)
.ignoreElements()
.startWith(msg)
)
那么我们要鼠标延迟delay
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)
})
为了更好地理解,请参阅上面提到的示例——我在那里添加了一些评论。
我有这个流 shows/hides 通知:
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 and this static viz example
主要技巧是至少等待
- 通知显示延迟
- 和流中的下一条消息
并让鼠标来回移动以增加延迟。
concatMap
内部的魔法可以做到这一点(至少,我认为是这样......)
开始,我们把notifications$
和concatMap延迟一下就可以了。因此,每条消息至少会显示 DELAY
次
注意:伪代码
notifications$.concatMap(msg =>
timer(DELAY)
.ignoreElements()
.startWith(msg)
)
那么我们要鼠标延迟delay
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)
})
为了更好地理解,请参阅上面提到的示例——我在那里添加了一些评论。