没有combineLatest从另一个observable获得价值的最好方法

时间:2016-03-07 04:26:51

标签: javascript rxjs observable

我有2个observable,其中基本上是2个dom事件。一个是'dragstart'事件,另一个是'drop'事件。 显然,dragStart将首先启动,并保持变量直到dropEvent Observable触发。

这是一个简单的例子,有助于澄清:

this.containerEl = document.querySelector...

var dragStart$ = Observable.fromEvent(this.containerEl, 'dragstart')
        .map((e) => e.target)

var dropEvent$ = Observable.fromEvent(this.containerEl, 'drop')
        .map((e) => e.target)

var subscription = dropEvent$.subscribe( (el) =>{
  el.appendChild( **NEED DRAGSTART EL HERE** )
})

我尝试在订阅上使用combineLatest(dragStart $,dropEvent $)但显然无效,因为dragStart $将在dropEvent $之前触发。

注意

我的目标是 NOT 使用外部状态。 IE:在dragStart $上设置一个全局变量,只需访问dropEvent $。

这有什么好的解决方案?我现在正在学习rxJS,所以任何专家意见都会受到赞赏!

2 个答案:

答案 0 :(得分:2)

由于您知道drop事件必须遵循dragStart事件,因此最好的方法是将拖放序列建模为单个observable。只有在收到开始事件后才开始观察掉落事件:

// observes start events
const start$ = Observable.fromEvent(this.containerEl, 'dragstart');
// will observe the *next* drop event
const nextDrop$ = Observable.fromEvent(this.containerEl, 'drop').take(1);

const dragDrop$ = start$
    // for each start event, listen for next drop event
    .flatMap({target: startEl} => nextDrop$
        // for drop event, return the start and end elements
        .map({target: endEl} => ({startEl, endEl})));

const subscription = dragDrop$.subscribe(({startEl, endEl}) => {
    endEl.appendChild(startEl);
});

答案 1 :(得分:0)

这是Rxjs的例子,是一个完美的解决方案。它使用.takeUntil(mouseup_event),因为当你按下鼠标时就完成了。没有外部状态

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

// Get the three major events
var mouseup   = Rx.Observable.fromEvent(dragTarget, 'mouseup');
var mousemove = Rx.Observable.fromEvent(document,   'mousemove');
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown');

var mousedrag = mousedown.flatMap(function (md) {

  // calculate offsets when mouse down
  var startX = md.offsetX, startY = md.offsetY;

  // Calculate delta with mousemove until mouseup
  return mousemove.map(function (mm) {
    mm.preventDefault();

    return {
      left: mm.clientX - startX,
      top: mm.clientY - startY
    };
  }).takeUntil(mouseup);
});

// Update position
var subscription = mousedrag.subscribe(function (pos) {
  dragTarget.style.top = pos.top + 'px';
  dragTarget.style.left = pos.left + 'px';
});