使用onclick与querySelectorAll()修改两组div属性的绑定问题
问题分析
你遇到的是循环中闭包变量绑定的问题:用var声明的box1和box2没有块级作用域,循环结束后,这两个变量会保留最后一次循环的赋值(也就是最后一组的box1和box2),所以不管点击哪一组元素,触发的事件都会操作最后一组的DOM。
解决方案
下面提供几种可行的修复方式:
方案1:用let代替var(最简单)
把循环里的var改成let,let会创建块级作用域,每次循环都会生成新的变量绑定,确保每个点击事件都能拿到当前循环对应的box1和box2:
<script type='text/javascript'> var box1Temp = document.querySelectorAll(".box1"); var box2Temp = document.querySelectorAll(".box2"); for (let i = 0; i < box1Temp.length; i++) { let box1 = box1Temp[i]; let box2 = box2Temp[i]; box2.onclick = box1.onclick = function() { if (box1.classList.contains("colorGreen")) { box1.classList.add("colorRed"); box1.classList.remove("colorGreen"); box2.innerHTML = "Text2"; } else { box1.classList.add("colorGreen"); box1.classList.remove("colorRed"); box2.innerHTML = "Text1"; } } } </script>
方案2:用闭包包裹(兼容旧浏览器)
如果要兼容不支持ES6的旧浏览器,可以用立即执行函数(IIFE)把每次循环的变量包裹起来,形成独立作用域:
<script type='text/javascript'> var box1Temp = document.querySelectorAll(".box1"); var box2Temp = document.querySelectorAll(".box2"); for (var i = 0; i < box1Temp.length; i++) { (function(box1, box2) { box2.onclick = box1.onclick = function() { if (box1.classList.contains("colorGreen")) { box1.classList.add("colorRed"); box1.classList.remove("colorGreen"); box2.innerHTML = "Text2"; } else { box1.classList.add("colorGreen"); box1.classList.remove("colorRed"); box2.innerHTML = "Text1"; } } })(box1Temp[i], box2Temp[i]); } </script>
方案3:用data-*属性关联对应元素(更灵活)
给每个box1和box2添加对应的索引,点击时通过索引找到配对的元素,不需要依赖循环变量:
修改后的HTML
<style> .colorGreen { background-color: green; } .colorRed { background-color: red; } </style> <div class="box2" data-index="0">Text1</div> <div class="box1 colorGreen" data-index="0">O</div> <div class="box2" data-index="1">Text1</div> <div class="box1 colorGreen" data-index="1">O</div> <div class="box2" data-index="2">Text1</div> <div class="box1 colorGreen" data-index="2">O</div>
修改后的JavaScript
<script type='text/javascript'> var box1List = document.querySelectorAll(".box1"); var box2List = document.querySelectorAll(".box2"); function toggleElements(index) { var box1 = box1List[index]; var box2 = box2List[index]; if (box1.classList.contains("colorGreen")) { box1.classList.add("colorRed"); box1.classList.remove("colorGreen"); box2.innerHTML = "Text2"; } else { box1.classList.add("colorGreen"); box1.classList.remove("colorRed"); box2.innerHTML = "Text1"; } } // 给所有box2绑定点击事件 box2List.forEach(function(box, index) { box.onclick = function() { toggleElements(index); } }); // 给所有box1绑定点击事件 box1List.forEach(function(box, index) { box.onclick = function() { toggleElements(index); } }); </script>
方案4:事件委托(更高效)
如果元素数量很多,推荐用事件委托,只给父元素绑定一次事件,通过事件冒泡判断点击的元素:
先给元素加父容器
<div class="container"> <div class="box2">Text1</div> <div class="box1 colorGreen">O</div> <div class="box2">Text1</div> <div class="box1 colorGreen">O</div> <div class="box2">Text1</div> <div class="box1 colorGreen">O</div> </div>
JavaScript代码
<script type='text/javascript'> var container = document.querySelector(".container"); var box1List = document.querySelectorAll(".box1"); var box2List = document.querySelectorAll(".box2"); container.onclick = function(e) { var target = e.target; // 点击的是box2 if (target.classList.contains("box2")) { var index = Array.from(box2List).indexOf(target); var box1 = box1List[index]; toggle(box1, target); } // 点击的是box1 else if (target.classList.contains("box1")) { var index = Array.from(box1List).indexOf(target); var box2 = box2List[index]; toggle(target, box2); } } function toggle(box1, box2) { if (box1.classList.contains("colorGreen")) { box1.classList.add("colorRed"); box1.classList.remove("colorGreen"); box2.innerHTML = "Text2"; } else { box1.classList.add("colorGreen"); box1.classList.remove("colorRed"); box2.innerHTML = "Text1"; } } </script>
内容的提问来源于stack exchange,提问作者Thornan
相关产品推荐
相关产品推荐

