javascript的事件冒泡,阻止事件冒泡和事件委托, 事件委托是事件冒泡的一个应用。
2018年12月13日更新
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> ul li{ border: 1px solid yellow; } </style> </head> <body> <p hidden>This content is not relevant to this page right now, so should not be seen. Nothing to see here. Nada.</p> <div id="ysr" style="border: 1px solid red;background-color: green;padding: 50px;"> <ul id="ljl"> <li id="1">aaaaaaaaa</li> <li id="2">aaaaaaaaa</li> <li id="3">aaaaaaaaa</li> <li id="4">aaaaaaaaa</li> <li id="5">aaaaaaaaa</li> <li id="6">aaaaaaaaa</li> <li id="7">aaaaaaaaa</li> <li id="8">aaaaaaaaa</li> <li id="9">aaaaaaaaa</li> </ul> </div> <script> var ljl = document.getElementById('ljl'); ljl.onclick = function (ev) { console.log(ev); console.log(ev.target); alert('in'); ev.stopPropagation(); }; function doSth(){ alert('---a---'); } function doSth2(){ alert('---ysr---'); } ljl.addEventListener('click',doSth,true) var ysr = document.getElementById('ysr'); ysr.addEventListener('click',doSth2,true) ysr.onclick = function (ev) { console.log(ev); console.log(ev.target); alert('in another'); } </script> </body> </html>
----------------------------------------------------------------------------------------------------------------------------------------------------------
首先,弄明白js 当中,什么是事件,事件模型在js中是如何设计的。什么是事件冒泡?
什么是“事件冒泡”呢?假设这里有一杯水,水被用某种神奇的方式分成不同颜色的几层。这时,从最底层冒出了一个气泡,气泡会一层一层地上升,直到最顶层。而你不管在水的哪一层观察都可以看到并捕捉到这个气泡。好了,把“水”改成“DOM”,把“气泡”改成“事件”。这就是“事件冒泡”
什么是事件委托呢?event delegation : 地址:http://davidwalsh.name/event-delegate
One of the hot methodologies in the JavaScript world is event delegation, and for good reason. Event delegation allows you to avoid adding event listeners to specific nodes; instead, the event listener is added to one parent. That event listener analyzes bubbled events to find a match on child elements. The base concept is fairly simple but many people don't understand just how event delegation works. Let me explain the how event delegation works and provide pure JavaScript example of basic event delegation.
下面是我在csdn找到的一篇解释,写的不错。原文地址:http://blog.csdn.net/iefreer/article/details/8573940
1、Event是什么?
event是用户操作网页时发生的交互动作,比如click/move, event除了用户触发的动作外,还可以是文档加载,窗口滚动和大小调整。
2、Event模型是什么?
Event模型指的是浏览器如何处理发生的事件。不同的浏览器其处理机制也不尽相同,甚至截然相反。
一般而言,某个界面元素发生单个事件,那么事件的处理对象就是该界面元素。
但一个典型的问题是如果该界面元素存在父子元素,而且父子元素也定义了同样的事件,
这个时候事件该如何处理呢,事件在父子元素之间是如何传递的呢,谁会先接收到这个事件,又是谁先处理呢?
举个例子:
----------------------------------- | element1 | | ------------------------- | | |element2 | | | ------------------------- | | | -----------------------------------
element2是element1的子元素,两者都定义了onclick事件。
这就是事件模型(事件序列)要解决的问题。
两种模型
回到网景和微软斗争的年代,两个公司选择了不同的道路:
网景选择的是事件捕获(event capturing)模型,即网景认为element1首先获取到事件;
微软选择了和其桌面系统类似的消息机制,认为element2有更高的优先权,即事件冒泡(event bubbling),
这两个模型截然相反,IE仅支持event bubbling. Mozilla, Opera 7等两种都支持. 更老版本的Opera和iCab两种都不支持。
你现在也许体会到了什么是互联网最初那最好也最坏的年代。
事件捕获
| | --------------- | |----------------- | element1 | | | | ----------- | |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
看上面箭头的方向,element1的事件处理器首先被触发,然后向下传递到element2
事件冒泡
/ \ --------------| |----------------- | element1 | | | | ----------- | |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
与事件捕获相反,element2的事件处理器会首先被触发。
W3C模型
W3C非常理智的处理了这种差异,在两者之间采取了中和的方法,W3C模型规定任何事件首先会被捕获直到遇到目标元素,然后再向上返回。
| | / \ -----------------| |--| |----------------- | element1 | | | | | | ---------------| |--| |----------- | | |element2 \ / | | | | | -------------------------------- | | W3C event model | ------------------------------------------
WEB开发人员可以通过addEventListener()
方法来选择在哪个阶段注册事件处理器(捕获阶段还是冒泡阶段),这个方法在Advanced models中有详细描述,其最后一个参数为true,则代表事件在捕获阶段被处理,false则代表事件在冒泡阶段被处理。
比如:
element1.addEventListener('click',doSomething2,true) element2.addEventListener('click',doSomething,false)
事件首先被element1捕获,然后执行doSomething2,接着事件传递给element2,doSomething被执行,接着,事件冒泡回溯,检查是否有父元素(element1)定义了冒泡阶段的事件处理器,这里没有,所以事件终止。
兼容传统模型
在支持W3C DOM的浏览器中,传统的事件注册被看作是注册于冒泡阶段。
element1.onclick = doSomething2;
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
例子: 原地址:http://www.pureweber.com/article/event-delegation/
<html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <style> .white{background-color:#fff;} #d1{width:400px;height:400px;border:1px solid #000;margin:50px 50px;} #d2{width:300px;height:300px;border:1px solid #000;margin:50px 50px;} #d3{width:200px;height:200px;border:1px solid #000;margin:50px 50px;} #d4{width:100px;height:100px;border:1px solid #000;margin:50px 50px;} </style> <script src="./lib/js/jquery-2.1.3.js"></script> </head> <body> <div id="d1" class="white"> <div id="d2" class="white"> <div id="d3" class="white"> <div id="d4" class="white"> </div> </div> </div> </div> <button id="reset1">重置</button> </body> <script> $('#d4').bind('click', function(e){ e.stopPropagation(); alert('冒泡被阻止,这块将不会改变颜色'); }); jQuery('#d1').click(function(e){ var t = jQuery(e.target); var id = t.attr('id'); if (id==='d4'){ t.css('background-color', 'yellow'); } else if (id==='d3') { t.css('background-color', 'green'); } else if (id==='d2') { t.css('background-color', 'blue'); } else { t.css('background-color', 'red'); } }); jQuery('#reset1').click(function(){jQuery('.white').css('background-color', '#fff')}); /* jQuery('#d4').click(function(){jQuery(this).css('background-color', 'yellow')}); jQuery('#d3').click(function(){jQuery(this).css('background-color', 'green')}); jQuery('#d2').click(function(){jQuery(this).css('background-color', 'blue')}); jQuery('#d1').click(function(){jQuery(this).css('background-color', 'red')}); jQuery('#reset1').click(function(){jQuery('.white').css('background-color', '#fff')}); */ </script> </html>
例子说明:注释的js 作用是显示出(事件冒泡和事件捕捉的):点击最小的那个,外面所有的都会被上色。你会发现,点击里层的正方形,外层所有的正方形都会被上色。因为它们也都捕捉到了点击事件。。未注释的是:修改上面的程序,使用事件委托来处理点击事件。 当最顶层捕获点击事件时,查看事件来源于哪一层,然后只将那一层涂色。再次点击每一层,查看实际效果。只有当前点击的正方形变色了,其他的都毫无反应。都“委托” 给了最顶层的那个div.当然,如果你有这样嵌套的页面元素,使用了事件委托,委托到了最顶层,这时需要注意:如果其中某个元素,你不希望它的事件冒泡,那么可以使用某种方式阻止事件的冒泡。在jQuery框架中,可以使用stopPropagation()方法来实现而不必关心浏览器兼容性。
事件委托的用途:事件委托是事件冒泡的一个应用,可以减少绑定元素的个数,也不必担心子节点被替换后可能需要进行重新的事件绑定。因为事件的捕获和后续代码的执行已经完全委托给了其父节点。如果页面中含有大量元素需要绑定事件,这样做会减少事件绑定数量,为浏览器减负,无疑会提高页面性能。