使用RXjs拖放

时间:2017-04-12 09:57:35

标签: drag-and-drop rxjs

我正在努力应对RXJS的拖放行为。我想在250ms鼠标按下后开始拖动一个元素,因为没有劫持该元素上的点击事件。

到目前为止,开始拖动工作但停止拖动永远不会被调用。谁知道为什么?

let button = document.querySelector('.button');

let mouseDownStream = Rx.Observable.fromEvent(button, 'mousedown');
let mouseUpStream = Rx.Observable.fromEvent(button, 'mouseup');

let dragStream = mouseDownStream
  .flatMap((event) => {
    return Rx.Observable
      .return(event)
      .delay(250)
      .takeUntil(mouseUpStream)
  });

let dropStream = mouseUpStream
  .flatMap((event) => {
    return Rx.Observable
      .return(event)
      .skipUntil(dragStream)
  });

dragStream.subscribe(event => console.log('start drag'));
dropStream.subscribe(event => console.log('stop drag'));

JSBin

2 个答案:

答案 0 :(得分:4)

我已经更新了您的代码示例以使其运行,我做了什么:

  • flatMap s交换switchMap s switchMapflatMapLatest的别名)这将确保它只接收最新事件以及新事件发出后,它将取消任何旧的subevent =>在这种情况下,flatMap可能会正常工作,但使用switchMap更安全,这也是一条经验法则:如有疑问:请使用switchMap
  • dropStream基于dragStream现在
  • 删除了skipUntil,这是一个竞赛条件问题,因为它会在一些mouseUp(需要及时返回)后的下一个dragStream发射之后首先触发。
  • 将mouseUp-target从button交换到document(更多的是一个方便的东西,而不是真正必不可少的工作)



let button = document.querySelector('.button');

let mouseDownStream = Rx.Observable.fromEvent(button, 'mousedown');
let mouseUpStream = Rx.Observable.fromEvent(document, 'mouseup');

let dragStream = mouseDownStream
  .switchMap((event) => {
    return Rx.Observable
      .return(event)
      .delay(250)
      .takeUntil(mouseUpStream)
  });

let dropStream = dragStream
  .switchMap(() => mouseUpStream.take(1))

dragStream.subscribe(event => console.log('start drag'));
dropStream.subscribe(event => console.log('stop drag'));

<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.all.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<button class="button">Button</button>
</body>
</html>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

具有TypeScript和更新的rxjs的通用拖动事件

export const DragEvent = (selector:string):Observable<boolean> => {

  //element where the drag event should be recorded (make sure element is in the dom)
  const elem = document.querySelector(selector);

  // touch events to handle mobile devices
  const touchStart$ = fromEvent<TouchEvent>(elem, 'touchstart');

  const touchEnd$ = fromEvent<TouchEvent>(elem, 'touchend');

  const touchMove$ = fromEvent<TouchEvent>(elem, 'touchmove');

  // mouse events for desktop users
  const mouseDown$ = fromEvent<MouseEvent>(elem, 'mousedown');

  const mouseUp$ = fromEvent<MouseEvent>(elem, 'mouseup');

  const mouseMove$ = fromEvent<MouseEvent>(elem, 'mousemove');

  //Mouse drag event
  const mouseDragging$ = mouseMove$.pipe(
    skipUntil(mouseDown$),
    takeUntil(mouseUp$)
  );

  // 
  const mapToBoolean = (bool) => map(() => bool);

  //universal drag event will emit true on drag (desktop/mobile) optional:add touchStart$ to the merge.
  const move$ = merge(mouseDragging$, touchMove$).pipe(mapToBoolean(true);

  //universal end of drag event will emit false on drag end (desktop/mobile)
  const end$ = merge(mouseUp$, touchEnd$).pipe(mapToBoolean(false);

  //merged to return true or false depending on user dragg
  return merge(move$, end$).pipe(distinctUntilChanged());

}