【问题标题】:Javascript - Dynamically assign onclick event in the loopJavascript - 在循环中动态分配 onclick 事件
【发布时间】: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 事件以显示对应选项!?

谢谢!

【问题讨论】:

    标签: javascript html events button 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); }
                  猜你喜欢
                  • 2017-09-18
                  • 2017-08-28
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-08-31
                  • 2013-03-29
                  • 1970-01-01
                  • 2012-10-29
                  • 2018-03-25
                  相关资源
                  最近更新 更多