Javascript 使用RxJS进行反应式编程-可以简化此滚动功能吗?

Javascript 使用RxJS进行反应式编程-可以简化此滚动功能吗?,javascript,functional-programming,reactive-programming,rxjs,Javascript,Functional Programming,Reactive Programming,Rxjs,我对反应式编程(和RxJS)相当陌生,所有这些操作符都很难理解 无论如何,我已经成功地编写了这个函数,它可以在拖动某些内容时处理文档的滚动。我现在想知道这是否可以简化 基本上,在MouseDown上,我需要每10毫秒检查一次鼠标的位置,当鼠标移动时,我需要更新的clientY,这就是为什么我设置了一个Rx.Oberservable.interval(10),我将它与mouseMove observer结合使用。这将滚动页面,无论您是否移动鼠标(如预期) 代码如下: handleWindowScr

我对反应式编程(和RxJS)相当陌生,所有这些操作符都很难理解

无论如何,我已经成功地编写了这个函数,它可以在拖动某些内容时处理文档的滚动。我现在想知道这是否可以简化

基本上,在MouseDown上,我需要每10毫秒检查一次鼠标的位置,当鼠标移动时,我需要更新的
clientY
,这就是为什么我设置了一个
Rx.Oberservable.interval(10)
,我将它与mouseMove observer结合使用。这将滚动页面,无论您是否移动鼠标(如预期)

代码如下:

handleWindowScrollOnDrag() {
    var dragTarget = this.getDOMNode()
    var scrollTarget = document.body
    var wHeight = window.innerHeight
    var maxScroll = document.documentElement.scrollHeight - wHeight

    // 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.flatMap(function (md) {
        var y = scrollTarget.scrollTop
        var multiplier = 1

        // Scroll every 10ms until mouseup when we can
        var intervalSource = Rx.Observable.interval(10).takeUntil(mouseup);

        // Get actual clientY until mouseup
        var movement = mousemove.map(function (mm) {
            return {
                y: mm.clientY
            };
        }).takeUntil(mouseup);

        return Rx.Observable
            .combineLatest(movement, intervalSource, function (s1) {
                multiplier = 1

                if (s1.y < 100 && y >= 0) {
                    if (s1.y < 75) multiplier = 3;
                    if (s1.y < 50) multiplier = 5;
                    if (s1.y < 25) multiplier = 10;
                    if (s1.y < 15) multiplier = 20;
                    y -= (1 * multiplier)
                }

                if (s1.y > wHeight - 100 && y <= (maxScroll)) {
                    if (s1.y > wHeight - 75) multiplier = 3;
                    if (s1.y > wHeight - 50) multiplier = 5;
                    if (s1.y > wHeight - 25) multiplier = 10;
                    if (s1.y > wHeight - 15) multiplier = 20;
                    y += (1 * multiplier)
                }

                return {
                    y: y
                };
        });
    });

    // Update position
    this.subscription = mousedrag.subscribe(function (pos) {
        document.body.scrollTop = pos.y
    });

},
handleWindowScrollOnDrag(){
var dragTarget=this.getDOMNode()
var scrollTarget=document.body
var wHeight=窗内高度
var maxScroll=document.documentElement.scrollHeight-wHeight
//获取三大事件
var mouseup=Rx.Observable.fromEvent(文档“mouseup”);
var mousemove=Rx.Observable.fromEvent(文档“mousemove”);
var mousedown=Rx.Observable.fromEvent(dragTarget,“mousedown”);
var mousedrag=mousedown.flatMap(函数(md){
变量y=scrollTarget.scrollTop
var乘数=1
//每10毫秒滚动一次,直到鼠标悬停
var intervalSource=Rx.可观察到的间隔(10).takeUntil(mouseup);
//在鼠标悬停前得到真正的客户
var movement=mousemove.map(函数(mm){
返回{
y:嗯,克利恩蒂
};
}).takeUntil(mouseup);
返回Rx。可观察
.CombineTest(移动、中断源、功能(s1){
乘数=1
如果(s1.y<100&&y>=0){
如果(s1.y<75)乘数=3;
如果(s1.y<50)乘数=5;
如果(s1.y<25)乘数=10;
如果(s1.y<15)乘数=20;
y-=(1*乘数)
}
如果(s1.y>wHeight-100和&y wHeight-75)乘数=3;
如果(s1.y>wHeight-50)乘数=5;
如果(s1.y>wHeight-25)乘数=10;
如果(s1.y>wHeight-15)乘数=20;
y+=(1*乘数)
}
返回{
y:y
};
});
});
//更新位置
this.subscription=mousedrag.subscripte(函数(pos)){
document.body.scrollTop=位置y
});
},

您可以删除额外的
Take,直到
移动流上只需要一个,因为
组合测试
操作符将在完成时清理并处置所有基础订阅

接下来,您可以使用
.scan
来管理累积状态,而不是闭包变量,从而删除一些额外的状态

您还可以通过简单地传递鼠标移动的
y
值来简化事件体,而不是在
map
combinelateest
操作符中产生对象分配的开销

最后,我将改为使用
.withLatestFrom
而不是
combinelatetest
。由于您已经基本上以100 fps的间隔轮询
CombineTest
,如果鼠标同时移动,则会发出更快的消息

顺便说一句,虽然我不太熟悉DOM滚动的工作原理(实际上我也不知道您的代码在野外的工作情况如何),但滥发页面的滚动值比页面的实际呈现速度要快似乎有些过头了。最好降低间隔率,并使用类似于
jQuery.animate
的方法来平滑中间的滚动

);tldr

handleWindowScrollOnDrag(){
var dragTarget=this.getDOMNode()
var scrollTarget=document.body;
var wHeight=窗内高度;
var maxScroll=document.documentElement.scrollHeight-wHeight;
//获取三大事件
var mouseup=Rx.Observable.fromEvent(文档“mouseup”);
var mousemove=Rx.Observable.fromEvent(文档“mousemove”);
var mousedown=Rx.Observable.fromEvent(dragTarget,“mousedown”);
var mousedrag=mousedown.flatMap(函数(md){
//每10毫秒滚动一次,直到鼠标悬停
var intervalSource=Rx.Observable.interval(10,Rx.Scheduler.requestAnimationFrame);
返回间隔源
.takeUntil(鼠标)
.withLatestFrom(鼠标移动,函数(s1,s2){
返回s2.clientY;
})
.scan(scrollTarget.scrollTop,函数(y,delta){
var乘数=1;
如果(增量<100&&y>=0){
如果(δ<75)乘数=3;
如果(δ<50)乘数=5;
如果(δ<25)乘数=10;
如果(δ<15)乘数=20;
y-=(1*乘数);
}
如果(delta>wHeight-100和&y wHeight-75)乘数=3;
如果(delta>wHeight-50)乘数=5;
如果(delta>wHeight-25)乘数=10;
如果(delta>wHeight-15)乘数=20;
y+=(1*乘法器);
}
返回y;
});
});
//更新位置
this.subscription=mousedrag.subscripte(函数(pos)){
document.body.scrollTop=pos;
});
},
编辑

原文中的错误实际上可以进一步简化代码。通过将
mousemove
传递到
withLatestFrom
并使用该结果选择器抓取
clientY

此外,我还添加了如果您尝试同步,您可能希望添加计划程序的位置
handleWindowScrollOnDrag() {
  var dragTarget = this.getDOMNode()
  var scrollTarget = document.body;
  var wHeight = window.innerHeight;
  var maxScroll = document.documentElement.scrollHeight - wHeight;

  // 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.flatMap(function (md) {
      // Scroll every 10ms until mouseup when we can
      var intervalSource = Rx.Observable.interval(10, Rx.Scheduler.requestAnimationFrame);

      return intervalSource
          .takeUntil(mouseup)
          .withLatestFrom(mousemove, function (s1, s2) {
              return s2.clientY;
           })
           .scan(scrollTarget.scrollTop, function(y, delta) { 
              var multiplier = 1;

              if (delta  < 100 && y >= 0) {
                  if (delta < 75) multiplier = 3;
                  if (delta < 50) multiplier = 5;
                  if (delta < 25) multiplier = 10;
                  if (delta < 15) multiplier = 20;
                  y -= (1 * multiplier);
              }

              if (delta > wHeight - 100 && y <= (maxScroll)) {
                  if (delta > wHeight - 75) multiplier = 3;
                  if (delta > wHeight - 50) multiplier = 5;
                  if (delta > wHeight - 25) multiplier = 10;
                  if (delta > wHeight - 15) multiplier = 20;
                  y += (1 * multiplier);
              }

              return y;
        });
  });

  // Update position
  this.subscription = mousedrag.subscribe(function (pos) {
      document.body.scrollTop = pos;
  });

},