在jQuery中循环绑定按钮点击事件失败,如何解决?
为什么循环绑定点击事件时无法弹出按钮ID?怎么解决?
嘿,这个问题其实是典型的闭包作用域陷阱,我来给你拆解一下原因和解决办法:
问题根源
你第一个循环能正常弹出ID,是因为循环执行时立刻就获取了对应索引的元素ID并弹窗——这是同步执行的,i的值在每一次循环里都是当前的正确值。
但第二个代码里,click事件是异步触发的:当你点击按钮的时候,循环早就跑完了!这时候var声明的i已经变成了循环结束后的len值(也就是按钮总数),而$(".btn-sm")[len]根本不存在(因为数组索引从0开始),自然不会有弹窗。
几种解决方法
我给你列几个实用的方案,按推荐程度排序:
1. 用jQuery的each方法(最推荐)
jQuery本身提供了遍历元素的方法,能完美避开闭包问题,代码也更直观:
$(function () { bind_button(); }); function bind_button() { // 遍历每个.btn-sm元素 $(".btn-sm").each(function() { // 给当前元素绑定点击事件 $(this).click(function() { // this就是当前被点击的按钮元素 alert(this.id); }); }); }
2. 直接绑定事件,不用循环(更简洁)
其实你甚至不需要单独写bind_button函数,直接给所有.btn-sm绑定点击事件就行,this会自动指向被点击的按钮:
$(function () { $(".btn-sm").click(function() { alert(this.id); }); });
3. 用ES6的let替代var
如果想保留你的循环写法,把var i改成let i就行——let有块级作用域,每次循环都会创建一个独立的i变量,点击事件能拿到当前循环的正确索引:
$(function () { bind_button(); }); function bind_button() { var len = $(".btn-sm").length; // 把var换成let for(let i = 0; i < len; i ++ ){ $(".btn-sm")[i].click(function (){ alert($(".btn-sm")[i].id); }); } }
4. 立即执行函数(IIFE)兼容旧环境
如果你的项目还需要兼容不支持ES6的旧浏览器,可以用立即执行函数把每次循环的i值“保存”下来:
$(function () { bind_button(); }); function bind_button() { var len = $(".btn-sm").length; for(var i = 0; i < len; i ++ ){ // 用IIFE创建独立作用域,把当前i传给index (function(index) { $(".btn-sm")[index].click(function (){ alert($(".btn-sm")[index].id); }); })(i); } }
内容的提问来源于stack exchange,提问作者Michael An
相关产品推荐
相关产品推荐

