循环事件绑定时js比较常用的一个功能,今天在实现的过程写了一个bug:button点击后报错“ Cannot read properties of undefined (reading ‘style’)”,经过一番查找后,分享给大家;
一.功能介绍
如下图有五个button,现在想实现点击后变色,同时其他颜色保持不变;
二.代码实现
乍一看,这个功能很简单,首先遍历button按钮,同时再绑定onclick事件,最后使用变量把循环值带出循环外,在循环开始时候清除上一个点击的样式就可以;
代码实现如下:
function exclusive() {
//获取button数组
var btnAll = document.querySelectorAll('#day_0508_test05 button');
var exclusiveButtonStyle = 0;//定义一个初始值
//遍历button
for (var i = 0; i < btnAll.length; i++) {
//绑定事件
btnAll[i].onclick = function () {
//初始化样式
btnAll[exclusiveButtonStyle].style.backgroundColor = '';
//选中的button置为粉色
this.style.backgroundColor = 'pink';
//获取索引,下一次循环时进行清除
exclusiveButtonStyle = i;
}
}
}
exclusive();
但是,执行后报错,提示无法获取btnAll[exclusiveButtonStyle]的样式;
三.原因分析:
经过仔细研究,获取不了btnAll[exclusiveButtonStyle]的值,那问题一定处在for循环和绑定onclick这里。经过打断点调试,发现,函数触发后,for循环的事件绑定是直接执行完毕的,与onclick是否触发没有关系!
换句话说:可以理解为onclick与for循环是异步进行的。
分析到这里,那么问题就水落石出了:
1.onclick与for循环是异步进行的;
2.for循环在触发onclick之前已经执行完毕,这时触发onclick,exclusiveButtonStyle获取到的i值应该是i最后的值,也就是5;
3.exclusiveButtonStyle超出button个数,遂报错。
四.解决方案:
知道了问题原因,那就好解决了:只要让每一次循环exclusiveButtonStyle都可以正确的获取i值就好了。
let声明变量表示块作用域,用let来声明for循环的i,可以让每一次循环的i值都不是一个值,这样exclusiveButtonStyle就可以获取正确i值;
改正后代码如下:
function exclusive() {
//获取button数组
var btnAll = document.querySelectorAll('#day_0508_test05 button');
var exclusiveButtonStyle = 0;//定义一个初始值
//遍历button 使用let声明变量
for (let i = 0; i < btnAll.length; i++) {
//绑定事件
btnAll[i].onclick = function () {
//初始化样式
btnAll[exclusiveButtonStyle].style.backgroundColor = '';
//选中的button置为粉色
this.style.backgroundColor = 'pink';
//获取索引,下一次循环时进行清除
exclusiveButtonStyle = i;
}
}
}
exclusive();