点击鼠标触发什么事件(鼠标点击弹出属性)
导语:鼠标点击li元素,弹出各自索引值
我主要是把鼠标点击li元素,弹出各自索引值的几种方法进行总结。
问题:如下代码所示有好多li元素。实现的效果是当鼠标点击某个li元素时弹出自己的索引值(当然这里不是弹出它的innerHTML,这是凑巧索引值和它的innerHTML相等)
<ul id="ul1"> <li>0</li> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul>12345678
我们通常的做法是:
var aLi=document.getElementById('ul1') .getElementsByTagName('li'); for(var i=0;i<aLi.length;i++) { aLi[i].onclick=function(){ alert(i); } }12345678
这是否如我们所愿呢,经过测试我们会发现,这段代码不管我们点击哪个都会弹出的是6.
这是为什么?
首先解释6是怎么来的,我们可以知道,这个循环的终止条件是i<aLi.length。也就是i不再<6。条件首次成立i 的值是6。因此,输出显示的是循环结束时i的最终值。
这里引入一个更深入的问题,代码中到底有什么缺陷导致它的行为同语义所暗示的不一致呢?
缺陷是我们试图假设循环中的每个迭代在运行时都会给自己“捕获”一个i的副本,但是根据作用域的工作原理,实际情况是尽管循环中的6个函数是在各个迭代中分别定义的,但是他们都被封闭在一个共享的全局作用域中,因此实际上只有一个i。
这样说的话,当然所有函数共享一个i的引用
我们可以通过声明并立即执行函数表达式来创建作用域。
var aLi=document.getElementById('ul1') .getElementsByTagName('li'); for(var i=0;i<aLi.length;i++) { (function(){ var j=i; aLi[j].onclick=function(){ alert(j); } })(); }123456789101112
当然我们也可以对这段代码进行改进
var aLi=document.getElementById('ul1') .getElementsByTagName('li'); for(var i=0;i<aLi.length;i++) { (function(j){ aLi[j].onclick=function(){ alert(j); } })(i); }1234567891011
当然,这些IIFE也不过就是函数,因此我们可以将i传递进去,至于参数的话名字随便起都行。
在迭代内使用IIFE会为每一个迭代都生成一个新的作用域,使得点击函数可以将新的作用域封闭在每个迭代内部,每个迭代中都会含有一个具有正确值的变量供我们访问。
考虑我们对前面的问题的解决方案的分析。我们是在每次迭代时都创建了一个新的作用域,换句话说,每次迭代我们都需要一个块作用域。我们可以使用let劫持块作用域。
var aLi=document.getElementById('ul1') .getElementsByTagName('li'); for(var i=0;i<aLi.length;i++) { let j=i;//闭包的块作用域 aLi[j].onclick=function(){ alert(j); } }123456789
我们可以进行代码优化
var aLi=document.getElementById('ul1') .getElementsByTagName('li'); for(let i=0;i<aLi.length;i++) { aLi[i].onclick=function(){ alert(i); } }12345678
for循环头部的let声明还会有一个特殊的行为。这个行为指出变量在循环过程中不止被声明一次,每次迭代都会声明。随后的每个迭代都会用上一个迭代结束时的值来初始化这个变量。
很酷是吧?块作用域和闭包联手,天下无敌。
最后我们再说一个方法
var aLi=document.getElementById('ul1').getElementsByTagName('li'); for(var i=0;i<aLi.length;i++) { aLi[i].index=i; aLi[i].onclick=function(){ alert(this.index); } }
本文内容由小姿整理编辑!