【问题标题】:RxJs: Drag and Drop example : add mousedragstartRxJs:拖放示例:添加 mousedragstart
【发布时间】:2016-03-11 21:51:28
【问题描述】:

如何使用Drag and Drop RxJs's example 实现mousedragstart Observable。

mousedragstart 应该在mousedown 之后的第一个mousedrag 之前发出,直到mouseup

我认为我们必须和flatMap/take(1)/takeUntil(mouseup)一起玩,但我每次都失败..


更新

这里的困难不是避免mousedragmousedragstart之前发出

【问题讨论】:

  • 诸如mousedrag = mousedown.flatMap(_ => mousemove).first().repeat() 之类的?我认为应该不会太远。

标签: javascript system.reactive rxjs


【解决方案1】:

基于我之前的非解决根问题的答案以及您提供的信息,我们在概念上定义如下:

var dragTarget = document.getElementById('dragTarget');

var mouseup   = Rx.Observable.fromEvent(document,   'mouseup');
var mousemove = Rx.Observable.fromEvent(document,   'mousemove');
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown');

var dragstart = mousedown.flatMap(() =>
  mousemove
   .where(x => x.movementX !== 0 || x.movementY !== 0)
   .takeUntil(mouseup)
   .take(1)
);

var dragmove = mousedown.flatMap(() =>
  mousemove
    .where(x => x.movementX !== 0 || x.movementY !== 0)
    .takeUntil(mouseup)
);

这里的问题是事件之间的重叠;就与底层事件的关系而言,dragstart 的触发与第一个 dragmove 完全相同。在这种情况下,订阅顺序将决定执行顺序,正如您所说,这不是您想要依赖的东西。为了解决这个问题,我们必须控制底层事件。

这是一个简单的函数,它接受一个 observable 并返回一个包含两个 observable 的数组,这两个 observable 将发出与原始 observable 相同的值,但其中的事件总是在第二个 observable 之前传递给第一个 observable,无论哪个先订阅:

function prioritize(s$) {
  var first = new Rx.Subject();
  var second = s$.do(x => first.onNext(x)).share();

  return [
    Rx.Observable.using(
      () => second.subscribe(() => {}),
      () => first
    ),
    second
  ];
}

从那里,我们可以用这样的东西替换上面的适当部分:

var mousedowns = prioritize(mousedown);

var dragstart = mousedowns[0].flatMap(() =>
 mousemove
   .where(x => x.movementX !== 0 || x.movementY !== 0)
   .takeUntil(mouseup)
   .take(1)
);

var dragmove = mousedowns[1].flatMap(() =>
  mousemove
    .where(x => x.movementX !== 0 || x.movementY !== 0)
    .takeUntil(mouseup)
);

dragmove.subscribe(() => console.log('dragmove'));
dragstart.subscribe(() => console.log('dragstart'));

这是整个工作:

https://jsbin.com/qodilerofe/edit?js,console,output

【讨论】:

  • 理解起来比较复杂,但效果很好!谢谢;)
【解决方案2】:

应该很简单

var mousedragstart = mousedown.flatMap(() => mousemove.takeUntil(mouseup).take(1));

但事实并非如此。 Chrome 在 mousedown 之后立即引发 mousemove 事件,这将导致上述逻辑在用户实际开始拖动之前错误地生成元素。所以你实际上需要这样的东西:

var mousedragstart = mousedown.flatMap(() =>
      mousemove
         .where(x => x.movementX !== 0 || x.movementY !== 0)
         .takeUntil(mouseup)
         .take(1)
);

【讨论】:

  • 它不起作用 dragmove 在 dragstart 之前发出。
  • 你所说的“dragmove”是什么?我查看了您链接的示例并重新阅读了您的问题,但我不完全确定您在问什么。您能否发布一些显示该问题的示例代码?
  • example code 我想在任何dragmove 之前获得dragstart
  • 啊。 dragstart 和 dragmove 本质上由相同的东西组成(dragstart 实际上只是第一个 dragmove,但您希望它在第一个 dragmove 之前立即发生)。因为它们都依赖于相同的潜在事件,所以它们总是会一起触发。哪个订阅先运行取决于哪个订阅先进行;解决问题所需要做的就是在订阅 dragmove 之前订阅 dragstart。
  • 是的,我看到了.. 但是想象一下,如果我正在创建一个图书馆,我不能告诉人们在订阅事件时尊重订单:) 我认为它应该存在一个解决方案在dragmove 之前发出这个dragstart(可能类似于startWith,但我不明白它也可以工作..)。如果不可能.. 我会在没有 RxJs 的情况下实现它。
【解决方案3】:

拖放的另一种解决方案:

let dragDiv = document.getElementById('drag');
let mouseisdown = false;
let startPos;

Observable.fromEvent(dragDiv, "mousedown").subscribe((e) => {
    mouseisdown = true;
    startPos = { x: e.offsetX, y: e.offsetY}
});
Observable.fromEvent(document, "mouseup").subscribe(e => mouseisdown = false); 


Observable
    .fromEvent(document, "mousemove")
    .filter(e => mouseisdown)
    .map((e) => {
        return   {
          left: e.clientX - startPos.x,
          top: e.clientY - startPos.y
        }
    })
    .subscribe( p => {
    dragDiv.style.top = p.top + "px";
    dragDiv.style.left = p.left + "px";
});

打字稿版本:

let dragDiv = document.getElementById('drag');
let mouseisdown = false;
let startPos;

Observable.fromEvent(dragDiv, "mousedown").subscribe((e:MouseEvent) => {
    mouseisdown = true;
    startPos = { x: e.offsetX, y: e.offsetY}
});
Observable.fromEvent(document, "mouseup").subscribe(e => mouseisdown = false); 


Observable
    .fromEvent(document, "mousemove")
    .filter(e => mouseisdown)
    .map((e:MouseEvent) => {
        return   {
          left: e.clientX - startPos.x,
          top: e.clientY - startPos.y
        }
    })
    .subscribe( p => {
    dragDiv.style.top = p.top + "px";
    dragDiv.style.left = p.left + "px";
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-12
    相关资源
    最近更新 更多