在 RxJS 中重新创建上下文菜单事件
Recreate contextmenu event in RxJS
我想在触摸时重新创建 contextmenu event from touch events in RxJS because iOS does not support 上下文菜单事件。
用简单的语言来说,这个 observable 应该在以下时间发出:
- 触摸启动事件发生
- 2000 毫秒(基本上是长按)
- 接着是触摸端
在以下情况下不应发出:
- 触摸结束发生在不到 2000 毫秒的时间内
- touchstart 事件之后是 touchmove 事件
如果 touchend 发生得更快或者 touchstart 之后是 touchmove,我不知道如何跳过。这是我到目前为止的内容:
const touchStart$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchstart");
const touchEnd$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchend");
const touchMove$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchmove");
const contextmenu$ = touchStart$.pipe(
switchMap(event => touchEnd$.pipe(mapTo(event))),
switchMap(event => timer(2000).pipe(mapTo(event), takeUntil(merge(touchEnd$, touchMove$))))
);
contextmenu$.subscribe($event => {
console.log("CONTEXTMENU EVENT HAPPENED");
});
我想出了一个可能的解决方案:
const touchStart$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchstart");
const touchEnd$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchend");
const touchMove$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchmove");
const contextmenu$ = touchStart$.pipe(
switchMap(event =>
timer(2000).pipe(
mapTo(event),
takeUntil(merge(touchMove$, touchEnd$)),
switchMap(event => touchEnd$.pipe(mapTo(event), takeUntil(touchMove$)))
)
)
);
contextmenu$.subscribe($event => {
console.log("CONTEXT MENU EVENT HAPPENED");
});
您的解决方案可以稍微简化一下。内部 mapTo
不是必需的,如果您不重复使用名称 event
,您可以在管道的末尾使用一个 mapTo
。此外,您可能希望在内部 switchMap
上使用 take(1)
而不是 takeUntil(touchMove$)
,因为您希望在第一次发射后结束流:
const longPress$ = this.touchStart$.pipe(
switchMap(event => timer(2000).pipe(
takeUntil(merge(touchMove$, touchEnd$)),
switchMap(() => touchEnd$.pipe(take(1))),
mapTo(event)
))
);
我假设你得到了你想要的行为,但我认为通常长按会在持续时间过去后触发;即我们不需要等待 touchend
事件。如果是这样,那就更简单了:
const longPress$ = this.touchStart$.pipe(
switchMap(event => timer(2000).pipe(
takeUntil(merge(touchMove$, touchEnd$)),
mapTo(event)
))
);
这里有几个 StackBlitzes 和丰富多彩的日志记录:Original | Simplified
我想在触摸时重新创建 contextmenu event from touch events in RxJS because iOS does not support 上下文菜单事件。
用简单的语言来说,这个 observable 应该在以下时间发出:
- 触摸启动事件发生
- 2000 毫秒(基本上是长按)
- 接着是触摸端
在以下情况下不应发出:
- 触摸结束发生在不到 2000 毫秒的时间内
- touchstart 事件之后是 touchmove 事件
如果 touchend 发生得更快或者 touchstart 之后是 touchmove,我不知道如何跳过。这是我到目前为止的内容:
const touchStart$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchstart");
const touchEnd$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchend");
const touchMove$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchmove");
const contextmenu$ = touchStart$.pipe(
switchMap(event => touchEnd$.pipe(mapTo(event))),
switchMap(event => timer(2000).pipe(mapTo(event), takeUntil(merge(touchEnd$, touchMove$))))
);
contextmenu$.subscribe($event => {
console.log("CONTEXTMENU EVENT HAPPENED");
});
我想出了一个可能的解决方案:
const touchStart$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchstart");
const touchEnd$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchend");
const touchMove$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchmove");
const contextmenu$ = touchStart$.pipe(
switchMap(event =>
timer(2000).pipe(
mapTo(event),
takeUntil(merge(touchMove$, touchEnd$)),
switchMap(event => touchEnd$.pipe(mapTo(event), takeUntil(touchMove$)))
)
)
);
contextmenu$.subscribe($event => {
console.log("CONTEXT MENU EVENT HAPPENED");
});
您的解决方案可以稍微简化一下。内部 mapTo
不是必需的,如果您不重复使用名称 event
,您可以在管道的末尾使用一个 mapTo
。此外,您可能希望在内部 switchMap
上使用 take(1)
而不是 takeUntil(touchMove$)
,因为您希望在第一次发射后结束流:
const longPress$ = this.touchStart$.pipe(
switchMap(event => timer(2000).pipe(
takeUntil(merge(touchMove$, touchEnd$)),
switchMap(() => touchEnd$.pipe(take(1))),
mapTo(event)
))
);
我假设你得到了你想要的行为,但我认为通常长按会在持续时间过去后触发;即我们不需要等待 touchend
事件。如果是这样,那就更简单了:
const longPress$ = this.touchStart$.pipe(
switchMap(event => timer(2000).pipe(
takeUntil(merge(touchMove$, touchEnd$)),
mapTo(event)
))
);
这里有几个 StackBlitzes 和丰富多彩的日志记录:Original | Simplified