动态分配的点击事件在Javascript中触发错误的操作

时间:2012-01-26 12:54:14

标签: javascript

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

下面是一个说明问题的摘录。

我会非常感谢解释为什么会发生这种情况以及我应该如何编码以克服这个问题。我猜这与分配的动态值有关,但我最初的想法是,这似乎没有逻辑行为!

<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>

3 个答案:

答案 0 :(得分: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”来获取正确的对象。

答案 1 :(得分:1)

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

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]); });
}

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

答案 2 :(得分:0)

随着更多的搜索(并感谢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'的回答也有效,所以我会接受这个正确答案。