js 多按钮事件响应 传参值重复问题
function initButtons()
{
var x = 0;
var y = 0;
var w = 1512;
var h = 1560;
var button = new Array();
for(y = 0; y * 30< h; y++)
for(x = 0; x * 36 < w; x++)
{
var n = (1 + y * 40 + x);
button[n] = document.createElement("input");
button[n].type = "button";
button[n].id = "detail" + n;
button[n].addEventListener('mouseover',function(){alert(x);});
button[n].addEventListener('mouseout',hideD);
button[n].style.cssText = "position:absolute;top:" + ((y + 1) * 30 - 8) + ";left:" + ((x + 1) * 36 - 8) + ";width:10;height:15;background:transparent;";
document.getElementById("buttons").appendChild(button[n]);
}
} 展开
这个问题是你在循环中的闭包导致的。
下面代码中,因为 mouseover 的回调函数形成了一个闭包,所以闭包中的 x 是调用的闭包外面的变量 x,而在循环结束之后,这个x 的值是42,所以无论在循环中的哪一次绑定事件,最后 x 都是42.
button[n].addEventListener( 'mouseover', function() { alert(x); } );
可以通过以下两种方法调整代码修复这个问题:
第一种:不要在循环中创建闭包,这是非常不推荐的写法,如果你用 JSHint 做代码检测,这个会报出一条警告。因为这种方法很危险,容易埋下隐患。所以要把 handler 函数定义在 initButtons 外面。这样有两种写法:
下面是第一种写法:
// 在 initButtons 函数外面定义函数 handler
function handler( x ) {
console.log( 'click', x );
}
// 将事件绑定的位置改写成这样
button[n].addEventListener( 'mouseover', handler.bind( button[n], x ) );
下面是第二种写法:
// 在 initButtons 函数外面定义函数 handler
function handler( x ) {
return function() {
console.log( x );
};
}
// 将事件绑定的位置改写成这样。
button[n].addEventListener( 'mouseover', handler( x ) );
第二种:依然在循环中创建闭包,但是改变传值方式
// 将事件绑定部分改成这样
button[n].addEventListener( 'mouseover', ( function( x ) {
return function() {
console.log( x );
};
} )( x ) );
首先膜拜一下大牛,提供了三种方法,经验证都是可行解
其次,说一下我出现这种问题的根本原因:
我错以为每次调用addEventListener函数,x的当前值都会自动被记录下来,而实际上并没有。我这样写回调函数只是单纯提供一个函数,这三种方法之所以能行,是因为这样写能在调用addEventListener函数的同时,回调函数部分会被执行一次,在返回一个函数的同时,将当前x的值也传递了过去~简直太完美!