首页 > 解决方案 > 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 完成而不发射?

标签: rxjsrxjs-pipeable-operators

解决方案


澄清:

  1. 如果鼠标按住超过 1 秒,您希望从 mouse_Hold$ 发出。
  2. 你想从 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


推荐阅读