【问题标题】:takeUntil failing to prevent emissions from observabletakeUntil 未能防止可观察到的排放
【发布时间】:2019-08-22 03:00:48
【问题描述】:

我正在尝试使用 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$ 和 mouse_Click$ 的内部 observable 在不发射的情况下完成?

【问题讨论】:

    标签: rxjs rxjs-pipeable-operators


    【解决方案1】:

    澄清一下:

    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

    【讨论】:

      【解决方案2】:

      直到需要在链的末端

      这将取消整个链。

      const { fromEvent } = rxjs;
      const { tap, takeUntil, mergeMap, merge } = rxjs.operators;
      
      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$
          ),
          takeUntil(mouse_Up$)
        ).subscribe(event => console.log("Drag"));
      <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>

      【讨论】:

      • 感谢阿德里安的回复。将 takeUntil 转移到外部 observable 的问题是它将完成这个 observable 并且不会发出未来的 mouse_drag$ 事件。即您只能拖动一次,然后不会注册其他拖动。
      • 实际上,如果您想完成 mouse_Hold$ 和 mouse_Click$ - 那么它们将停止发射 - 这是预期的。或者你想重新创建它们?如果鼠标拖动超过 1 秒,则使结果可观察到一次发射。然后重复这个逻辑?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-09
      • 1970-01-01
      相关资源
      最近更新 更多