7

我有一个完全依赖于 JavaScript 和 Ajax 的三步过程来加载数据并动画化从一步到下一步的过程。更复杂的是,步骤之间的过渡(向前和向后)是动画的:-(。当用户通过流程锚点的进度出现时,会显示当前步骤和之前的步骤。如果他们点击了之前的步骤,那么它会将他们带回到上一步。

现在,整个过程(向前和向后)正常工作,如果您从第 1 步开始,但如果您直接跳到第 3 步,则第 1 步和第 2 步的锚点也会执行与第 3 步相同的操作。

这是代码的一部分,它循环遍历所有步骤直到用户将要执行的当前步骤,并依次显示每个锚点并将适当的函数分配给点击事件:

for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', function(){
            pm.loadData(action, dao_id, true);
        });

        Effect.Appear('step_anchor_' + i, {
            duration: 1,
            delay: (down_delay++)
        });
    }
}

我知道问题在于传递 action 和 dao_id 参数的方式。我也尝试过传递 profile.steps[i].action 和 profile.steps[i].dao_id 但在这种情况下 profile 和 i或者至少我不在范围内。

如何做到这一点,以便我可以为每个步骤正确分配 action 和 dao_id 的参数?(如果有什么不同,我们使用的是 Prototype 和 Scriptaculous)

4

2 回答 2

7

您的封闭范围链导致了您的问题。通过内联声明处理函数,您已经创建了一个闭包。显然,您这样做是为了利用循环。

但是,由于您已经创建了一个闭包,因此您正在按照闭包范围规则进行操作。这些规则规定,只要闭包存在,父函数中的局部变量就会保持活动和可用。

您正在尝试将“action”和“dao_id”传递给您的闭包,但您在这里传递的是引用,而不是值。因此,当您的闭包(处理程序)被调用时,它们使用上次分配引用的值。在您的情况下,第 3 步处理程序。

闭包范围规则已经够混乱了,但你也可能会因为“action”和“dao_id”在循环块已经执行完毕的情况下仍然存在这一事实而感到困惑。好吧,在 JavaScript 中没有块作用域之类的东西。一旦你声明了一个变量,它在函数结束或被删除之前都是可用的。以先到者为准。

综上所述,您需要打破作用域链。这里有两种方法可以做到这一点:

试试这个:

for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', function(a, b){
                return function(){pm.loadData(a, b, true)};
        }(action, dao_id));

        Effect.Appear('step_anchor_' + i, {
                duration: 1,
                delay: (down_delay++)
        });
    }
}

或这个:

function createHandler(action, dao_id) {
    return function(){pm.loadData(action, dao_id, true);};
} 

/* snip - inside some other function */
for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', createHandler(action, dao_id));
        Effect.Appear('step_anchor_' + i, {
                duration: 1,
                delay: (down_delay++)
        });
    }
}
于 2008-11-24T23:31:36.133 回答
0

首先,记住你在点击事件中的执行范围。该上下文中的this关键字指的是被单击的元素。有什么方法可以从被点击的元素中确定 dao_id 吗?

于 2008-11-24T22:38:01.920 回答