在没有 combineLatest 的情况下从另一个可观察对象获取价值的最佳方法
Best way to get value from another observable without combineLatest
我有 2 个可观察对象,其中基本上是 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$ 之前触发。
注意
我的目标是不在此使用外部状态。 IE:在 dragStart$ 上设置一个全局变量,然后在 dropEvent$ 上访问。
对此有什么好的解决方案?我现在正在学习 rxJS,所以任何专家意见都将不胜感激!
因为您知道放置事件必须跟在 dragStart 事件之后,所以最好的方法是将 drag/drop 序列建模为单个可观察对象。收到开始事件后才开始观察掉落事件:
// 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);
});
这正是来自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';
});
我有 2 个可观察对象,其中基本上是 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$ 之前触发。
注意
我的目标是不在此使用外部状态。 IE:在 dragStart$ 上设置一个全局变量,然后在 dropEvent$ 上访问。
对此有什么好的解决方案?我现在正在学习 rxJS,所以任何专家意见都将不胜感激!
因为您知道放置事件必须跟在 dragStart 事件之后,所以最好的方法是将 drag/drop 序列建模为单个可观察对象。收到开始事件后才开始观察掉落事件:
// 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);
});
这正是来自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';
});