javascript事件是所有网页互动性的根本,因此在我们编写前端交互的时候,事件绑定作为再普通不过的交互操作了。在传统的事件处理中,你根据需求给每一个元素添加或者 删除事件处理器,然而事件处理器可以导致内存泄露或者性能下降(你用的越多风险越大)。例如以下例子
一:当我们点击每个li时,控制台打出 当前点击元素的 innerHtml
1 <ul id="ul"> 2 <li>aaaaaaaa</li> 3 <li>bbbbbbbb</li> 4 <li>cccccccc</li> 5 </ul>
传统的做法:为每个li绑定点击事件:
1 window.onload = function(){ 2 var ul = document.getElementById("ul"); 3 var lis = ul.getElementsByTagName("li"); 4 for(var i = 0 ; i < lis.length; i ++){ 5 lis[i].onclick = function(){ 6 console.log(this.innerHTML); 7 } 8 } 9 }
这样我们就可以做到li上面添加鼠标事件,但是如果说我们可能有很多个li用for循环的话就比较影响性能。
实际开发情况中,我们的li大多数是根据数据集合,动态组装生成的。此时就需要我们每生成一个li 就给这个li 绑定一个点击事件。效率低,容易出错
思考:1.有没有一种可行的方法让我每次只需完成一次事件绑定的操作?
2.或者我在li的父容器上,加入某种事件,让我在每次点击li时,由父容器的事件判断我当前点击的哪个li元素,并执行特定的操作?
答:事件代理。
下面我们可以用事件代理的方式来实现这样的效果。html不变
1 window.onload = function(){ 2 var ul = document.getElementById("ul"); 3 var lis = ul.getElementsByTagName("li"); 4 5 ul.onclick = function(e){ 6 /* 7 这里要用到事件源:event 对象,事件源,不管在哪个事件中,只要你操作的那个元素就是事件源。 8 ie:window.event.srcElement 9 标准下:event.target 10 nodeName:找到元素的标签名 11 */ 12 var e = e || window.event; 13 var target = e.target || e.srcElement; 14 if(target.nodeName.toUpperCase() == "LI"){ 15 alert(target.innerHTML); 16 } 17 } 18 }
这样,我们就使用事件代理完成在父容器绑定点击事件,当我们点击子元素li时,根据事件源得到当前点击的target元素。这样就算li是动态生成的,在点击的时候也会去获取到新的节点li。并执行对应操作。
原理:事件冒泡以及目标元素。当一个元素的事件被触发时,同样的事件将会在这个元素的所有祖先元素中被触发,这一过程称之为事件冒泡。这个事件从原始元素一直冒泡到dom树最上层。并且所有的事件触发的目标元素都是最开始的元素(target || srcElement)因此我们可以根据这一原理来达到触发原始元素事件的目的。
这样做的好处:
1.将所有同类元素的事件操作代理给其父元素,减少了事件绑定过程,避免了100个li,1000个li 或者更多li的循环绑定事件,有效减少内存占用,避免元素过多导致浏览器内存泄露,提高效率。
2.在DOM更新后无须重新绑定事件处理器了。
注:1.并不是所有的时间都允许事件冒泡,blur、focus、load和unload不能像其它事件一样冒泡
2.阻止事件冒泡操作:event.stopPropagation();
总结:了解事件代理的原理后,实现起来就很简单了。事件代理大大减少了事件处理器的增加删除操作。开发过程中,根据实际的项目需求,合理使用事件代理 以来提高浏览器效率。 一些主流类库也提供了事件代理示例,例如(jquery)等。