一个经典的例子,给 ul>li 下面的每个 li 节点添加点击事件,让其弹出当前 li 元素的索引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<ul id="testUL"> <li> index = 0</li> <li> index = 1</li> <li> index = 2</li> <li> index = 3</li> </ul> <script type="text/javascript"> var nodes = document.getElementsByTagName("li"); for (var i = 0; i < nodes.length; i += 1) { nodes[i].onclick = function () { console.log(i); } } </script>
运行上述代码后就会发现,每次打印的结果都显示为4,而不是真正的索引值。这是因为点击事件的匿名函数发生在for循环之后,而for循环执行完毕时 i 的值就为4,所以点谁都是同样的结果。那么这个时候就能通过立即执行函数 + 闭包的方法解决此问题:
1 2 3 4 5 6 7 8 9 10 11
<scripttype="text/javascript"> var nodes = document.getElementsByTagName("li"); for (var i = 0; i < nodes.length; i += 1) { nodes[i].onclick = (function (i) { // 1. IIFE创建一个函数作用域 returnfunction () { // 4. 返回这个匿名函数,延长作用域链 // 3. 内部嵌套的匿名函数使用到了IIFE的参数i,形成闭包 console.log(i); } })(i); // 2. 给IIFE传递每次for循环的i } </script>
这个时候触发click事件,打印的值就是li元素的索引了。
高级排他
这个例子有点像上面的,现在我们要个需求:在一个 ul li 列表中,鼠标移入时高亮当前li标签,移除之前li标签的高亮状态。
常规写法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 假设给li添加active类可以让标签高亮 window.onload = function() { let list = document.querySelectorAll('li') // 遍历每个标签 for (let i = 0; i < list.length; i++) { const li = list[i] li.onmouseover = function() { // mouseover触发后遍历整个列表,将所有标签class设为空 for (let j = 0; j < list.length; j++) { list[j].className = '' } // 最后给当前li标签添加active this.className = 'active' } } }