rxjs - takeUntil 未能防止可观察到的排放
问题描述
我正在尝试使用 Rxjs 和 mousedown、mouseup 和 mousemove 事件创建自己的单击、按住和拖动事件。我的尝试使用了许多以 mousedown 事件开头的流,每个流都有一个 takeUntil 来监听来自其他流的发射。基本上,一旦其中一个流“声明”了该操作(即通过了所有要求并发出了一个值),其他 observables 应该在没有排放的情况下完成。
我查看了其他答案,并认为它可能与运行异步的计时器有关,但它发生在不依赖计时器的流之间,例如拖动和单击。我一直在使用 rxjs v6 在 codesandbox.io 中玩耍。
takeUntil 也必须坐在内部 observables 上,因为我不希望外部 observables 运行一次并完成。
代码如下所示:
const mouse_Down$ = fromEvent(document, "mousedown").pipe(
tap(event => event.preventDefault())
);
const mouse_Up$ = fromEvent(document, "mouseup").pipe(
tap(event => event.preventDefault())
);
const mouse_Move$ = fromEvent(document, "mousemove");
const mouse_drag$ = mouse_Down$
.pipe(
mergeMap(mouseDownEvent =>
mouse_Move$.pipe(takeUntil(merge(mouse_Up$, mouse_Hold$, mouse_drag$)))
)
).subscribe(event => console.log("Drag"));
const mouse_Hold$ = mouse_Down$
.pipe(
mergeMap(mouseDownEvent =>
timer(1000).pipe(takeUntil(merge(mouse_drag$, mouse_Click$)))
)
).subscribe(event => console.log("Hold"));
const mouse_Click$ = mouse_Down$
.pipe(
mergeMap(mouseDownEvent =>
mouse_Up$.pipe(takeUntil(mouse_drag$, mouse_Hold$))
)
).subscribe(event => console.log("Click"));
预期行为:
如果用户在 mousedown 事件的 1 秒内移动鼠标,则mouse_drag$
流应该开始发射并且mouse_Click$/mouse_Hold$
的内部 observables 应该完成(感谢takeUntil(mouse_drag$)
没有发射并等待下一次发射mouse_down$
。
如果鼠标按钮在不移动的情况下保持按下状态超过 1秒,则mouse_Hold$
应该发出并且mouse_drag$/mouse_click$
的内部 observable 应该完成(感谢takeUntil(mouse_Hold$)
没有发出并等待下一次发射mouse_down$
。
实际行为:当前mouse_Drag$
会发出,mouse_Hold$
一秒后mouse_Click$
会发出,松开按钮时会发出。
我的问题是为什么发射mouse_Drag$
流不会导致mouse_Hold$
andmouse_Click$
的内部 observable 完成而不发射?
解决方案
澄清:
- 如果鼠标按住超过 1 秒,您希望从 mouse_Hold$ 发出。
- 你想从 mouse_drag$ 中获取值,如果 LESS 然后在鼠标下拉和 mouseMove 之后经过 1 秒。
您不必完成任何事情,否则所有行为都只会起作用一次。所以计划: 3. mouse_drag$ - 如果 mousedown - 检查 mouseMove 1 秒。如果 mouseMove 发出 - 切换到 mouseMove 值 4. mouse_Hold$ - 如果 mouseDown - 检查 mouseMove 1 秒。如果 mouseMove 没有发出 - 切换到 mouseHold 并使其发出 'Hold'
let Rx = window['rxjs'];
const {defer, of, timer, fromEvent, merge, race} = Rx;
const {switchMap, repeat, tap, takeUntil, filter} = Rx.operators;
const {ajax} = Rx.ajax;
console.clear();
const mouse_Down$ = fromEvent(document, "mousedown");
const mouse_Up$ = fromEvent(document, "mouseup");
const mouse_Move$ = fromEvent(document, "mousemove");
const timer$ = timer(2000);
mouse_Hold$ = mouse_Down$.pipe(
switchMap((downEvent) => {
return timer$.pipe(
switchMap((time) => of('HOLD'))
);
}),
takeUntil(merge(mouse_Up$, mouse_Move$)),
repeat(mouse_Down$)
)
mouse_Hold$.subscribe(console.warn);
mouse_drags$ = mouse_Down$.pipe(
switchMap(() => mouse_Move$),
takeUntil(mouse_Up$, $mouse_Hold),
repeat(mouse_Down$)
)
mouse_drags$.subscribe(console.log);
这是一个代码笔: https ://codepen.io/kievsash/pen/oOmMwp ?editors=0010
推荐阅读
- android - 颤振在 sliver 列表上每 x 次添加一个项目
- sqlite - 在 SQLite 房间中捕获批量插入的返回值
- node.js - 数组到 TS 中的类型化对象
- node.js - 节点路径问题 old-`/usr/bin/node` new-`/usr/local/bin/node`。无法安装任何软件包。如何更改路径(ubuntu 用户)
- python - 为什么我们在实现 Attention 时需要手动 for 循环?
- reactjs - 无限滚动 - data.map 未使用反应挂钩定义
- sqlite - 带有外键的 Sqlite DELETE 触发器
- netlify - 在同一 URL 上部署 Saas 和登录页面
- excel - LEFT MID RIGHT 在 Excel 中提取字符串中特定字符后的文本
- java - 将按钮对齐到中心,我在做什么?