Javascript 创建可观察的';已完成';RxJS中的事件
给定:,您将如何订阅一个丢弃事件 我修改了代码以订阅一个“已完成”回调,但它没有完成Javascript 创建可观察的';已完成';RxJS中的事件,javascript,reactive-programming,rxjs,Javascript,Reactive Programming,Rxjs,给定:,您将如何订阅一个丢弃事件 我修改了代码以订阅一个“已完成”回调,但它没有完成 (function (global) { function main () { var dragTarget = document.getElementById('dragTarget'); var $dragTarget = $(dragTarget); // Get the three major events var mo
(function (global) {
function main () {
var dragTarget = document.getElementById('dragTarget');
var $dragTarget = $(dragTarget);
// Get the three major events
var mouseup = Rx.Observable.fromEvent(document, 'mouseup');
var mousemove = Rx.Observable.fromEvent(document, 'mousemove');
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown');
var mousedrag = mousedown
.filter(function(md){
//console.log(md.offsetX + ", " + md.offsetY);
return md.offsetX <= 100
||
md.offsetY <= 100;
})
.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';
},
function(errorToIgnore) {},
function() { alert('drop');});
}
main();
}(window));
(功能(全局){
函数main(){
var dragTarget=document.getElementById('dragTarget');
变量$dragTarget=$(dragTarget);
//获取三大事件
var mouseup=Rx.Observable.fromEvent(文档“mouseup”);
var mousemove=Rx.Observable.fromEvent(文档“mousemove”);
var mousedown=Rx.Observable.fromEvent(dragTarget,“mousedown”);
var mousedrag=mousedown
.filter(函数(md){
//log(md.offsetX+“,”+md.offsetY);
return md.offsetX类似于这样的东西应该可以达到目的
(function (global) {
function main () {
var dragTarget = document.getElementById('dragTarget');
// Get the three major events
var mouseup = Rx.Observable.fromEvent(document, 'mouseup');
var mousemove = Rx.Observable.fromEvent(document, 'mousemove');
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown');
var drop = mousedown
.selectMany(
Rx.Observable
.concat(
[
mousemove.take(1).ignoreElements(),
mouseup.take(1)
]
)
);
}
main();
}(window));
编辑:
如果您将一个可观察函数视为一个异步函数,该函数产生多个值,然后可能完成或出错,那么您将立即认识到只能有一个完成事件
当您开始编写多个函数时,最外层的函数仍然只完成一次,即使该函数中包含多个函数。因此,即使“完成”的总数为3,最外层的函数仍然只完成一次
基本上,这意味着,如果假设最外层的函数在每次拖动完成时都返回一个值,那么您需要一种实际执行该操作的方法。您需要将拖动完成转换为最外层可观察的“onNext”事件
任何你能做的事情都会得到你想要的。也许这是最外层的函数返回的唯一类型的事件,或者它也会返回拖动开始和移动,但是只要它返回拖动完成,你就会得到你需要的(即使你以后不得不过滤它)
我上面给出的示例只是返回最可见外部阻力降的一种方法。OP的官方示例链接已关闭,如下所示:
对于最初的问题,有两种解决方案,一种是使用在官方示例上扩展的原始鼠标事件,另一种是原生HTML5拖放事件
由“mouseup”、“mousedown”和“mousemove”组成
首先,我们使用mousedown1.switchMapTo(mousemove.takeUntil(mouseup.take(1))
来获取“拖动开始”流。switchMapTo
()使用展平(将“mousedown1”映射到“鼠标移动直到鼠标向上”(也称为“拖动”)和切换的组合,为我们提供最新的mousedown1
emit,然后拖动,即不仅仅是在框上单击鼠标时
另一个“mousedown”流mousedown2
用于组成mousedrag
流,这样我们可以在拖动时不断渲染长方体。上面的mousedown1
优先于mousedown2
。有关更多信息,请参阅
一旦我们有了“拖动开始”流,我们就可以通过以下方式获得“拖动停止”流:mousedragstart.mergeMapTo(mouseup.take(1))
mergeMapTo
()将“mousedragstart”映射到“mouseup”的第一次发射,从而得到最新的“mousedragstart”和“mouseup”,后者本质上是“拖动停止”
下面的演示适用于RxJS v5:
const{fromEvent}=Rx.Observable;
const target=document.querySelector('.box');
const events=document.querySelector(“#events”);
const mouseup=fromEvent(目标“mouseup”);
const mousemove=fromEvent(文档“mousemove”);
const[mousedown1,mousedown2]=优先级克隆(fromEvent(target,'mousedown');
const mousedrag=mousedown2.mergeMap((e)=>{
const startX=e.clientX+window.scrollX;
const startY=e.clientY+window.scrollY;
const startedft=parseInt(e.target.style.left,10)| 0;
const startTop=parseInt(e.target.style.top,10)| 0;
返回mousemove.map((e2)=>{
e2.preventDefault();
返回{
左:startedft+e2.clientX-startX,
顶部:startTop+e2.clientY-startY
};
}).takeUntil(mouseup);
});
//将最新的鼠标向下发射映射到第一个鼠标拖动发射,即按下并拖动后发射
//然后拖动。
const mousedragstart=mousedown1.switchMapTo(mousemove.takeUntil(mouseup.take)(1));
//将鼠标拖动开始流映射到鼠标上行流的第一个发射,即在拖动和
//然后释放鼠标按钮。
const mousedragstop=mousedragstart.mergeMapTo(mouseup.take(1));
mousedrag.subscribe((pos)=>{
target.style.top=pos.top+'px';
target.style.left=pos.left+'px';
});
mousedragstart.subscribe(()=>{
log('drawing started');
events.innerText='已开始拖动';
});
mousedragstop.subscribe(()=>{
log('drawing stopped');
events.innerText='已停止拖动';
});
函数优先级克隆(流$){
const first=新的Rx.Subject();
const second=stream$.do(x=>first.next(x)).share();
返回[
可观察的使用(
()=>second.subscribe(()=>{}),
()=>首先
),
第二
];
}
.box{
位置:相对位置;
宽度:150px;
高度:150像素;
背景:海格林;
光标:指针;
}
好的,那就行了。非常感谢。现在我只需要弄清楚原因!我希望有一个更优雅的解决方案来强制可观察对象在上“完成”。takeUntil(mouseup);谢谢你的解释!让我如此困惑的是组成的顺序有多重要。公平地说,对于大多数函数式编程来说,顺序并不重要吗?我认为,来自一个相当天真的linq背景,我希望Rx具有与SQL相同的“顺序独立性”。如果有人链接到说到这里,我将不胜感激!顺序在SQL中是绝对重要的。如果您反转左连接的查询,会发生什么?您得到的不是更多就是更少