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中是绝对重要的。如果您反转左连接的查询,会发生什么?您得到的不是更多就是更少