JavaScript:将onclick附加到“while”循环中的链接

JavaScript: Attach onclick to a link inside "while" loop

本文关键字:while 循环 链接 onclick JavaScript      更新时间:2023-09-26

>我在将onclick附加到循环中的每个链接对象时遇到问题,当您单击链接时,它似乎总是返回与循环中第一项相关的数据,无论单击了什么。我需要单击每个链接以具有该链接的相关href

在下面的示例中,无论单击了哪个链接,控制台.log始终显示"http://example.com/link1/"

网页示例

  <li>
    <h2><a class="t" href="http://example.com/link1/"><i>Link 1 text</i></a></h2>
    <div class="panel" >Content</div>
  </li>
  <li>
    <h2><a class="t" href="http://example.com/link2/"><i>Link 2 text</i></a></h2>
    <div class="panel" >Content</div>
  </li>
  <li>
    <h2><a class="t" href="http://example.com/link3/"><i>Link 3 text</i></a></h2>
    <div class="panel" >Content</div>
  </li>
</ul>

JavaScript:

(function(){
  var theh2s = document.getElementById("panelList").getElementsByTagName("h2"), 
  i = theh2s.length;
  while (i--) {
      var getTheLinks = theh2s[i].getElementsByTagName("a");
      if (getTheLinks){
        if (getTheLinks[0].href){
          console.log(getTheLinks[0].href);
          getTheLinks[0].onclick = function() {
            console.log(getTheLinks[0].href);
            _gaq.push(['_trackEvent', 'Homepage', 'AB Click - Test B', getTheLinks[0].href]);
          };

        }
      }
  }
})();

问题是当发生单击时,getTheLinks已经设置为列表中的最后一个h2。为了防止每个循环覆盖前一个循环,您必须使用闭包使用此模式创建一个新上下文:(function(i){...})(i)

正如Felix Kling所提到的,关闭实际上是问题的根源。以下文章可以启发您了解此概念。有一段关于你刚刚遇到的这个常见陷阱:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures。

(function () {
    var theh2s = document.getElementById("panelList").getElementsByTagName("h2"),
        i = theh2s.length;
    while (i--) {
        (function (i) {
            var getTheLinks = theh2s[i].getElementsByTagName("a");
            if (getTheLinks) {
                if (getTheLinks[0].href) {
                    console.log(getTheLinks[0].href);
                    getTheLinks[0].onclick = function () {
                        console.log(getTheLinks[0].href);
                        _gaq.push(['_trackEvent', 'Homepage', 'AB Click - Test B', getTheLinks[0].href]);
                    };
                }
            }
        })(i);
    }
})();

我不熟悉JSLint。如果你需要 JSLint 有效,我想你必须像这样将函数定义移到循环之外:

while (i--) {
    f(i)
}
function f(i) {
    // same as above
}

我将继续演示我的首选解决方案。

(function(){
  function processLinkClick(e) {
    var link = e.currentTarget;
    console.log(link.href);
    _gaq.push(['_trackEvent', 'Homepage', 'AB Click - Test B', link.href]);
  }
  var theh2s = document.getElementById("panelList").getElementsByTagName("h2"), 
  i = theh2s.length;
  while (i--) {
      var getTheLinks = theh2s[i].getElementsByTagName("a");
      if (getTheLinks){
          if (getTheLinks[0].href){
              console.log(getTheLinks[0].href);
              getTheLinks[0].onclick = processLinkClick;

          }
      }
   }
})();

。是的,该功能可以内联,我只是将其分解以更清晰。

请记住,事件

函数接收一个事件对象,如果可能的话,它应该是您用来建立处理事件的上下文的唯一内容。 在这种情况下,上下文是"单击的链接",事件回答了该问题,而不是封闭上下文。 从软件设计的角度来看,我认为使用这个事件将是一个更干净的解决方案,从长远来看更容易维护。