使用代码了解JavaScript中的Reactive Extensions

时间:2012-09-11 18:07:30

标签: javascript reactive-programming

我是 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>

1 个答案:

答案 0 :(得分:3)

有这方面的描述。我建议看一下this video about Writing your first Rx Application。 C#中的代码,但无论编程语言如何,概念都完全相同。

基本上你想要理解3件事

  1. 将一系列事件概念化为序列。就像一个 数组是空间中的数据序列,事件可以被认为是一个 及时(或运动)的数据序列。
  2. 运营商(即SkipZipSelectManyTakeUntil
  3. 订阅语义
  4. 在这种情况下,我们有3个源序列; mouseMovemouseUpmouseDown

    每次移动鼠标时,mouseMove序列都会按下鼠标坐标的值。例如,如果鼠标从屏幕的左上角开始并沿对角线方向向下移动,那么您可能会在序列上看到{0,0}{10,10}{20,10}等值。

    mouseUpmouseDown发布的值并不重要,只是它们发布的时间点很有趣。

    “拖动”的实际问题要求我们知道何时按下鼠标按钮以及鼠标按下时鼠标所在位置的增量,以及释放按钮时的位置。我们获得这些位置的增量的方法是获取最终位置的值并减去原始位置的值。更好的是,如果我们可以获得所有中间delta值,那么我们就可以为运动设置动画。如果我们采用上面的序列,为了获得运动的增量,我们希望得到原始序列和一个序列

    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的简单数学运算。 这给了我们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事件时,我们都希望获得所有delta事件(mouseMoves)。

    var mouseDrags = mouseDown.SelectMany(function(md) { return mouseMoves;});
    

    但是我们只想继续接收它们,直到相应的mouseUp事件发生。要执行此操作,我们TakeUntil mouseUp事件会生成一个值。

    var mouseDrags = mouseDown.SelectMany(function(md) {
      return mouseMoves.TakeUntil(mouseUp);
    });
    

    现在我们完成了所有这些管道工作,我们通常将这些移动应用于UI元素的位置/边距/偏移量。它出现在示例中,我们只打印该值。