我是Reactive Extensions和JavaScript的新手。有人可以帮我拧开以下代码吗?来自Matthew Podwysocki's Introduction to the Reactive Extensions to JavaScript。
<html>
<head>
<title>Learning ReactiveExtensions</title>
<!--scripts-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script src="rx.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
var mouseDragMe = $("#mouseDragMe").context;
var mouseMove = Rx.Observable.FromHtmlEvent(mouseDragMe, "mousemove");
var mouseUp = Rx.Observable.FromHtmlEvent(mouseDragMe, "mouseup");
var mouseDown = Rx.Observable.FromHtmlEvent(mouseDragMe, "mousedown");
var mouseMoves = mouseMove
.Skip(1)
.Zip(mouseMove, function(left, right) {
return { x1 : left.clientX,
y1 : left.clientY,
x2 : right.clientX,
y2 : right.clientY };
});
var mouseDrags = mouseDown.SelectMany(function(md) {
return mouseMoves.TakeUntil(mouseUp);
mouseDrags.Subscribe(function(mouseEvents) {
$("#results").html(
"Old (X: " + mouseEvents.x1 + " Y: " + mouseEvents.y1 + ") " +
"New (X: " + mouseEvents.x2 + " Y: " + mouseEvents.y2 + ")");
});
});
});
</script>
</head>
<body>
<div id="mouseDragMe" style="border:solid 1px red;">
i am a rx newbie
</div>
</body>
</html>
最佳答案
那里对此有描述。我建议查看this video about Writing your first Rx Application。代码使用C#,但无论使用哪种编程语言,概念都完全相同。
本质上你想了解三件事
将一系列事件概念化为序列。就像一个
数组是空间中的数据序列,事件可以被认为是
时间(或运动)中的数据顺序。
运算符(即Skip
,Zip
,SelectMany
和TakeUntil
)
订阅语义
在这种情况下,我们有3个源序列。 mouseMove
,mouseUp
和mouseDown
。
每次移动鼠标时,mouseMove
序列都会推送鼠标坐标的值。例如,如果鼠标从屏幕的左上角开始,然后沿对角线向下移动,则笔直穿过屏幕,您可能会在序列上看到诸如{0,0}
,{10,10}
,{20,10}
之类的值。mouseUp
和mouseDown
发布的值并不有趣,只是发布它们的时间点很有趣。
实际的“拖动”问题要求我们知道何时按下鼠标按钮,以及按下鼠标时鼠标在何处以及释放按钮时在何处。我们获得这些头寸的差值的方法是获取最终头寸的值,再减去原始头寸的值。更好的是,如果我们可以获取所有中间增量值,以便可以对运动进行动画处理。如果我们采用上面的序列,则要获得运动增量,我们希望拥有原始序列,然后偏离一个序列
Original { 0, 0}, {10,10}, {20,10}
offby1 {10,10}, {20,10}
这使我们能够计算出增量来计算运动(而不仅仅是位置)。
Original { 0, 0}, {10,10}, {20,10}
offby1 {10,10}, {20,10}
delta {10,10}, {10, 0}
我们可以使用Rx实现此目的的方法是首先使用
Skip(1)
跳过一个值。这将创建我们的offby1
序列。接下来,我们要成对组合值。 Zip
函数为我们提供了此功能(my blog post about Combining sequences with Zip中有更多信息)。我们可以重写上面的代码
var mouseMoves = mouseMove
.Skip(1)
.Zip(mouseMove, function(left, right) {
return { x1 : left.clientX,
y1 : left.clientY,
x2 : right.clientX,
y2 : right.clientY };
});
成为
var offby1 = mouseMove.Skip(1);
var mouseMoves = offby1.Zip(mouseMove, function(left, right) {
return { x1 : left.clientX,
y1 : left.clientY,
x2 : right.clientX,
y2 : right.clientY };
});
一旦有了对,就需要应用
newValue-OldValue=delta
的简单数学。这给出了我们的增量序列,这实际上是我们的运动序列。
var offby1 = mouseMove.Skip(1);
var mouseMoves = offby1.Zip(mouseMove, function(current, last) {
return { x : current.clientX-last.clientX,
y : current.clientY-last.clientY };
});
现在,我们只想在鼠标按下时获取值。为此,我们使用SelectMany运算符。也就是说,对于来源中的每个值,请从该来源中获取0个或多个值。在我们的案例中,每次发生
mouseDown
事件时,我们都希望获取所有增量事件(作为mouseMoves
)。var mouseDrags = mouseDown.SelectMany(function(md) { return mouseMoves;});
但是,我们只希望继续接收它们,直到发生相应的
mouseUp
事件为止。为此,我们TakeUntil
mouseUp
事件产生一个值。var mouseDrags = mouseDown.SelectMany(function(md) {
return mouseMoves.TakeUntil(mouseUp);
});
现在我们已经完成了所有这些工作,我们通常将这些移动应用于UI元素的Position / Margin / offset。它出现在示例中,尽管我们只打印了该值。