说说事件委托
事件委托,说白了就是本来你要给一个元素添加一个事件(比如点击),出于某些考率,现在要把事件添加给它的外层元素。
事件源
解释事件委托之前,应该先了解下事件源。简单来说,事件源就是直接触发事件的元素。在事件函数中可通过event对象的target属性访问事件源。
看一个例子:
图中,单击span部分,控制台会打印出对应span元素;单击span外的p部分,会打印出对应p元素;单击p外的div部分,会打印出对应div元素。
关键代码如下:
1 <body> 2 <div id="box">div 3 <p>p 4 <span>span</span> 5 </p> 6 </div> 7 </body> 8 <script> 9 window.onload=function(){ 10 var box=document.getElementById("box"); 11 box.onclick=function(ev){ 12 console.log((ev || window.event).target); 13 }; 14 </script>
事件委托
再说事件委托。通常,我们用事件委托解决两问题:1、避免不必要的性能开销;2 、新生成的元素不需要重新添加事件。
先看一个经典的例子:
例子中,我们希望点击li能打印对应的文本。
1 <body> 2 <ul id="list"> 3 <li>red</li> 4 <li>green</li> 5 <li>blue</li> 6 <li>pink</li> 7 <li>black</li> 8 </ul> 9 </body> 10 <script> 11 var list=document.getElementById("list"); 12 var lis=document.querySelectorAll("li"); 13 14 for(var i=0;i<lis.length;i++){ 15 lis[i].onclick=function(){ 16 console.log(this.firstChild.nodeValue); //本来单击li,可以打印出其对应文本 17 }; 18 } 19 20 list.innerHTML+='<li>yellow</li>'; //这里加了一行后,单击li就无法打印出li对应文本了 21 </script>
本来,单击li是可以在控制台打印对应文体的。但是,现在20行加了一行代码,单击li就无法打印出li对应文本了。因为innerHTML会将原有内容全部清空,再赋予新内容,所以li绑定的单击事件也将失效。类似这种情况的还有,使用cloneNode(),新节点不会复制源节点的事件;jQuery中通过remove()移除的节点,重新添加回来后,之前绑定的事件将失效。(PS:detach()在这点上与remove()不同。)
下面,我将上面代码中的for循环换成以下代码:
1 list.onclick = function(ev){ 2 var ev = ev || window.event; 3 if(ev.target.tagName.toLowerCase()=='li'){ 4 console.log(ev.target.innerHTML); //单击li,即事件源是li是打印出其对应文本 5 } 6 };
这样就解决了刚才遇到的问题,而且避免了使用for循环。其实,在这个解决方案中,我们是把点击事件绑定在了li的父级元素ul身上,也就是所谓的事件委托。然后对事件源进行判断,等于间接地给li添加了点击事件。
本作品采用知识共享署名 4.0 国际许可协议进行许可。