我有一个完全依赖于 JavaScript 和 Ajax 的三步流程来加载数据并使流程从一步到下一步动画化。更复杂的是,步骤之间的过渡(向前和向后)是动画的:-(。随着用户在流程 anchor 中的进展,显示当前步骤和之前的步骤。如果他们点击之前的步骤,那么它将把他们带回到上一步。
现在,如果您从第 1 步开始,整个过程(向前和向后)都可以正常工作,但如果您直接跳到第 3 步,那么第 1 步和第 2 步的 anchor 也会执行与第 3 步相同的操作。
这是循环遍历用户将要进行的当前步骤的所有步骤的代码部分,并依次显示每个 anchor 并将适当的函数分配给点击事件:
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 或至少 i 不在范围内。
我该怎么做才能为每个步骤正确分配 action 和 dao_id 的参数? (如果有任何不同,我们使用的是 Prototype 和 Scriptaculous)
最佳答案
您的闭包作用域链导致了您的问题。通过内联声明处理函数,您已经创建了一个闭包。显然,您这样做是为了利用循环。
但是,由于您已经创建了一个闭包,所以您是在按照闭包作用域规则进行操作。这些规则规定,只要闭包存在,父函数中的局部变量就会保持事件状态并可用。
您正在尝试传递然后使用“action”和“dao_id”到您的闭包,但您在这里传递的是引用,而不是值。因此,当您的闭包(处理程序)被调用时,它们使用引用最后分配的值。在您的例子中,第 3 步处理程序。
闭包作用域规则已经够令人困惑了,但您可能还会对“action”和“dao_id”仍然存在这一事实感到困惑,即使循环 block 已完成执行。好吧,在 JavaScript 中没有 block 作用域这样的东西。一旦你声明了一个变量,它就一直可用,直到函数结束或者直到它被删除。以先到者为准。
综上所述,您需要打破作用域链。有两种方法可以做到这一点:
试试这个:
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++)
});
}
}
关于javascript - 如何将带有参数的事件处理程序添加到 Javascript 中的元素数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/315712/