当事件发生后,这个事件就要开始传播。例如咱们点击一个按钮时,就会产生一个click事件,但这个按钮自己不能处理这个事件,事件必须从这个按钮传播出去,从而到达可以处理这个事件的代码中。从里到外,直至它被处理,或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)javascript
(1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。html
IE 5.5: div -> body -> documentjava
IE 6.0: div -> body -> html -> documentnode
Mozilla 1.0: div -> body -> html -> document -> windowjquery
(2)捕获型事件(event capturing):事件从最不精确的对象(document 对象)开始触发,而后到最精确的对象web
(3)DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件,可是,捕获型事件先发生。两种事件流会触及DOM中的全部对象,从document对象开始,也在document对象结束。浏览器
DOM2.0模型将事件处理流程分为三个阶段:1、事件捕获阶段,2、事件目标阶段,3、事件起泡阶段。如图:函数
事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程当中,事件相应的监听函数是不会被触发的。this
事件目标:当到达目标元素以后,执行目标元素该事件相应的处理函数。若是没有绑定监听函数,那就不执行。spa
事件起泡:从目标元素开始,往顶层元素传播。途中若是有节点绑定了相应的事件处理函数,这些函数都会被一次触发。若是想阻止事件起泡,可使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。
每一个 event 都有一个event.bubbles
属性,能够知道它能否冒泡。
对于须要给不少列表式元素添加事件时,能够直接将事件添加到它们的父节点,将事件委托给父节点来触发处理函数。利用浏览器的事件冒泡机制实现单个元素事件处理
假设有一个ul 的父节点包含一些列li的子节点,但愿实现的效果是:鼠标移到li上时弹出悬浮窗,即li须要出发处理事件,一般写法是给每一个li绑定onclick等监听事件。
//html: <ul id="parent"> <li id="child1">Item 1</li> <li id="child2">Item 2</li> <li id="child3">Item 3</li> <li id="child4">Item 4</li> <li id="child5">Item 5</li> </ul>
js代码:
//js: function addListeners(li_child){ li_child = function clickHandler(){...}; } window.onload = function(){ var ul_parent = document.getElementById("parent"); var li_childs = ulNode.getElementByTagName("li"); for(var i=0, l = li_childs; i < l; i++){ addListener(li_childs[i]); } }
若是这个ul中的li子元素会频繁地添加或者删除,咱们就须要在每次添加li的时候都调用这个addListener方法来为每一个li节点添加事件处理函数。这就添加的复杂度和出错的可能性。
更简单的方法是使用事件代理机制,当事件被抛到更上层的父节点的时候,咱们经过检查事件的目标对象(target)来判断并获取事件源Li。下面的代码能够完成咱们想要的效果:
// 获取父节点,并为它添加一个click事件 document.getElementById("parent").addEventListener("click",function(e) { // 检查事件源e.targe是否为Li if(e.target && e.target.nodeName.toUpperCase == "li") { // 真正的处理过程在这里 ... } });
为父节点添加一个click事件,当子节点被点击的时候,click事件会从子节点开始向上冒泡。父节点捕获到事件以后,经过判断e.target.nodeName来判断是否为咱们须要处理的节点。而且经过e.target拿到了被点击的Li节点。从而能够获取到相应的信息,并做处理。
delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数,使用 delegate() 方法的事件处理程序适用于当前或将来的元素(好比由脚本建立的新元素)。
$("#parent").delegate("li", "click", function(){ // "$(this)" is the node that was clicked ... });
jQuery的delegate的方法须要三个参数,一个选择器,一个时间名称,和事件处理函数。
经过上面的介绍,你们应该可以体会到使用事件委托对于web应用程序带来的几个优势:
1.管理的函数变少了。不须要为每一个元素都添加监听函数。对于同一个父节点下面相似的子元素,能够经过委托给父元素的监听函数来处理事件。
2.能够方便地动态添加和修改元素,不须要由于元素的改动而修改事件绑定。
3.JavaScript和DOM节点之间的关联变少了,这样也就减小了因循环引用而带来的内存泄漏发生的几率。
网页中的某些元素是有本身的默认行为的,好比果超连接单击后须要跳转,提交按钮点击后须要提交表单,有时须要阻止这些行为,也就是默认行为,jQuery对这个问题进行了必要的扩展和封装
$("element").bind("click",function(event){ }); //event为事件对象event.stopPropagation(); //中止事件冒泡
jquery中可用用preventDefault()的方法来阻止元素的默认行为
$('#submit').bind('click', function(event) { var username = $('#username').val(); if (username == "") { alert('用户名不能为空!'); event.preventDefault(); //阻止默认行为 } })
jquery中对冒泡和默认行为的阻止方法能够改写,改写后可以达到一样的效果
event.preventDefault(); 改写为: return false; event.stopPropagation(); 改写为: return false;