【问题标题】:Dynamically Assigned Click Events Triggering Wrong Action in Javascript动态分配的点击事件触发 Javascript 中的错误操作
【发布时间】:2012-01-26 12:54:14
【问题描述】:

我正在循环遍历一个 Javascript 数组,通过 ID 将事件附加到元素。我可以看到添加了正确的事件,但是,当我点击链接触发事件时,它们都显示“链接6”被点击,而不是我想要的!

下面是一个说明问题的sn-p。

如果能解释为什么会发生这种情况,以及我应该如何编码来克服这个问题,我将不胜感激。我猜这与分配的动态值有关,但我最初的想法是这似乎不符合逻辑!

<html>
<body>
<p id='link1'>Link 1</p>
<p id='link2'>Link 2</p>
<p id='link3'>Link 3</p>
<p id='link4'>Link 4</p>
<p id='link5'>Link 5</p>
<p id='link6'>Link 6</p>

<script type='text/javascript'>

var sections = new Array('link1', 'link2', 'link3', 'link4', 'link5', 'link6');

    for (var section in sections) {
        console.log('Attaching event to ' + sections[section] );    
        document.getElementById(sections[section]).addEventListener('click', function(e){ alert('click '+sections[section]); });
    }

</script>
</body>

【问题讨论】:

    标签: javascript


    【解决方案1】:

    这行得通:

    <html>
    <body>
    <p id='link1'>Link 1</p>
    <p id='link2'>Link 2</p>
    <p id='link3'>Link 3</p>
    <p id='link4'>Link 4</p>
    <p id='link5'>Link 5</p>
    <p id='link6'>Link 6</p>
    
    <script type='text/javascript'>
    
    var sections = new Array('link1', 'link2', 'link3', 'link4', 'link5', 'link6');
    
    for (var section in sections) {
        console.log('Attaching event to ' + sections[section] );    
        document.getElementById(sections[section]).addEventListener('click', function(e){ alert('click '+ this.getAttribute("id")); });
    }
    

    尝试在回调函数中使用“this”来获取正确的对象。

    【讨论】:

      【解决方案2】:

      这是因为闭包的工作原理。 在行中

      for (var setting in settings){}
      

      您在每次迭代中为setting 变量分配一个新值。但是,作为事件处理程序附加的函数会保留对循环本地变量的引用。因此,在第二次迭代中,您正在更改值,该值也被第一次中创建的函数拾取,因为变量 section 的值绑定到迭代中的值。到最后一次迭代,所有函数都具有相同的引用。

      你可以很容易地避免这个问题,如下所示:

      var sections = new Array('link1', 'link2', 'link3', 'link4', 'link5', 'link6');
      
      for (var section in sections) {
          console.log('Attaching event to ' + sections[section] );    
          document.getElementById(sections[section]).addEventListener('click', function(e){
          var section = section;
          alert('click '+sections[section]); });
      }
      

      这样,您将为每个函数创建一个本地引用。

      【讨论】:

      • 这似乎不起作用 :( 使用同名变量 (var section = section;) 返回“未定义”。使用新变量 (var s = section;) 显示相同行为和以前一样。
      【解决方案3】:

      通过更多搜索(并感谢 sys.stderr 指出我要关闭),我找到了almost identical question with a very detailed answer about scope。

      建议的解决方案是使用 'with' 更改循环范围:-

      var sections = new Array('link1', 'link2', 'link3', 'link4', 'link5', 'link6');
      
      for (var section in sections) {
          with({x:section}) {
              console.log('Attaching event to ' + sections[x] );    
              document.getElementById(sections[x]).addEventListener('click', function(e){
              alert('click '+sections[x]); });
          }
      }
      

      gabitzish 关于使用“this”的回复也有效,所以我会接受这个正确的答案。

      【讨论】:

        猜你喜欢
        • 2012-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-23
        • 2016-06-03
        • 2015-04-05
        • 2015-10-04
        相关资源
        最近更新 更多