javascript - 如何将带有参数的事件处理程序添加到 Javascript 中的元素数组?

标签 javascript event-handling prototypejs dom-events

我有一个完全依赖于 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/

相关文章:

javascript - 使用 HTML5/JavaScript 构建数据网格

javascript - 使用 JQuery 获取图像的标题并将其显示为 HTML

javascript - 在何处添加事件监听器的最佳实践

event-handling - 为长轮询发出用户特定的事件

javascript - prototype.js 突出显示单词。 DOM 正确高效遍历

javascript - Youtube api - 停止视频

javascript - JS : How to prevent form being submited several times?

c++ - 如何管理C++键盘事件?

javascript - 使用 Prototype 从另一个域加载 JavaScript 文件

javascript - 如何在原型(prototype)中运行数组中的函数对象