Javascript 使用RxJS进行反应式编程-可以简化此滚动功能吗?
我对反应式编程(和RxJS)相当陌生,所有这些操作符都很难理解 无论如何,我已经成功地编写了这个函数,它可以在拖动某些内容时处理文档的滚动。我现在想知道这是否可以简化 基本上,在MouseDown上,我需要每10毫秒检查一次鼠标的位置,当鼠标移动时,我需要更新的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
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;
});
},