Javascript - 在循环中动态分配 onclick 事件

Posted

技术标签:

【中文标题】Javascript - 在循环中动态分配 onclick 事件【英文标题】:Javascript - Dynamically assign onclick event in the loop 【发布时间】:2011-06-29 17:32:40 【问题描述】:

我有一个非常简单的带有 js 代码的 html 页面:

<html>
    <head>
        <title></title>
    </head>
    <body>

        <div id="divButtons">

        </div>

        <script type="text/javascript">
            var arrOptions = new Array();

            for (var i = 0; i < 10; i++) 
                arrOptions[i] = "option" + i;
            

            for (var i = 0; i < arrOptions.length; i++) 
                var btnShow = document.createElement("input");
                btnShow.setAttribute("type", "button");
                btnShow.value = "Show Me Option";
                var optionPar = arrOptions[i];
                btnShow.onclick = function() 
                    showParam(optionPar);
                

                document.getElementById('divButtons').appendChild(btnShow);
            

            function showParam(value) 
                alert(value);
                    
        </script>
    </body>
</html>

该页面绑定了 10 个按钮,但是当您单击任何按钮时,它总是显示警报“option9”。如何分配 onclick 事件以显示对应选项!?

谢谢!

【问题讨论】:

【参考方案1】:
  pp();

  function pp()
  

    for(j=0;j<=11;j++)
    

      if(j%4==0)
      
        html+= "<br>";
      
      html += "<span class='remote' onclick='setLift(this)' >"+ j+"</span>";
    
    document.getElementById('el').innerHTML = html;
  

  function setLift(x)
  
    alert(x.innerHTML);
  

【讨论】:

【参考方案2】:

接受的答案是正确的,但我觉得没有做真正的解释。

让我试着解释一下,这里的问题是经典的缺少闭包。

每次循环迭代,变量“i”都会增加 1, 而on-click事件实际上并没有被执行,无论是否只应用于a元素,它都会被汇总到arrOptions的长度为10。

所以,循环一直持续到 'i' 为 10, 然后,每当触发点击事件时,它都会取 i 的值,即 10。

现在,对于解决方案, 在解决方案中,我们使用了闭包,因此当我们将“i”的值应用于 a 元素的点击事件时,它实际上会及时获得 i 的确切值。

onclick 事件的内部函数创建一个闭包,它引用参数 (arrOptions[i]),这意味着实际的 i 变量在正确的时间是什么。

函数最终以该值安全关闭, 然后可以在执行点击事件时返回其对应的值。

【讨论】:

【参考方案3】:

接受的答案似乎有效,但似乎令人困惑并且有点麻烦。更好的方法可能是为您要为其分配事件侦听器的元素使用 data 属性。它简单,易于理解,并且代码更少。这是一个例子:

btnShow.data = arrOptions[i];

btnShow.onclick = function() 
  showParam(this.data);

【讨论】:

【参考方案4】:

您只将变量的引用传递给函数,而不是它的值。因此,每次循环迭代时,它都会为您的匿名函数分配一个引用,并且它们都指向内存中的相同值。但是由于您在循环中使用相同的变量名,因此您会覆盖变量的值。您可以将变量连接到字符串以保留其值。比如这样:

btnShow.onclick = new Function("", "showParam(" + arrOptions[i] + ");");

第一个参数是函数的名称,但它是可选的(可以留空或完全省略)。

【讨论】:

【参考方案5】:

对于 jquery,请查看API 中的添加事件数据部分:

...
for (var i = 0; i < arrOptions.length; i++) 

    $('<input id="btn" type="button" value="Show Me Option"><input>').appendTo("#divButtons")

    $('#btn').bind("click", 
        iCount: i,
    function(event) 
        showParam(arrOptions[iCount]);
    );

【讨论】:

【参考方案6】:

我附加了一个事件处理程序:

        window.onload = function() 
            var folderElement;
            tagFolders = document.getElementById("folders");
            for (i = 0; i < folders.length; i++) 
                folderElement = folderButtons[i];
                folderElement = document.createElement("button");
                folderElement.setAttribute("id", folders[i]);
                folderElement.setAttribute("type", "button");
                folderElement.innerHTML = folders[i];
                if (typeof window.addEventListener !== "undefined") 
                    folderElement.addEventListener("click", getFolderElement, false);
                 else 
                    folderElement.attachEvent("onclick", getFolderElement);
                
                tagFolders.appendChild(folderElement);
            

它可以从触发事件的元素中检索任何东西:

// This function is the event handler for the folder buttons.
function getFolderElement(event) 
    var eventElement = event.currentTarget;
    updateFolderContent(eventElement.id);

在这种情况下,您必须将选项嵌入到元素/标签中。在我的情况下,我使用 id。

【讨论】:

【参考方案7】:

考虑当 onclick() 函数被执行时,它所拥有的只是:

showParam(optionPar);

,逐字逐句。 optionPar 将在单击事件执行时解析,此时它很可能是您分配给它的最新值。您通常应该避免以这种方式传递变量。

你要解决的问题最好通过重写以下文章来解决:

            btnShow.value = "Show Me Option";
            var optionPar = arrOptions[i];
            btnShow.optionPar = optionPar;
            btnShow.onclick = function(e) 
                // if I'm not mistaking on how to reference the source of the event.
                // and if it would work in all the browsers. But that's the idea.
                showParam(e.source.optionPar);
            

【讨论】:

【参考方案8】:

你必须这样做:

btnShow.onclick = (function(opt) 
    return function() 
       showParam(opt);
    ;
)(arrOptions[i]);

【讨论】:

这里实际发生了什么?这对我也有用,但我也想理解:-) @MartinElvar 他创建了一个参数是 opt 的函数,然后当我们应用 (...)(arrOptions[i]) 然后它被传递给 opt 然后当我们点击 btnShow 然后这个函数使用已设置的参数调用。 一个更好的方法是使用节点的“data”属性,然后使用this.data作为函数的参数,这不会让人感到困惑。这是一个示例:btnShow.data = arrOptions[i]; btnShow.onclick = function() showParam(this.data);

以上是关于Javascript - 在循环中动态分配 onclick 事件的主要内容,如果未能解决你的问题,请参考以下文章

在 Javascript 的 for 循环中分配点击处理程序

如何在javascript中将动态ID放在复选框中?

for 循环期间的动态分配会造成内存泄漏吗?

如何在 C 中找到动态分配数组的大小?

在使用 php for 循环生成 div 并为它们动态分配 ids 后,我如何使用 jquery 定位 ids?

为啥在使用 realloc() 进行动态内存分配之后再添加一块内存?