浏览器中的事件捕获和冒泡

js是一门事件驱动的编程语言,事件一般有多种,好比说网络事件,IO事件,定时事件,点击事件等等。 在这里先只关注下前端浏览器中的事件。前端

什么事件

如同字面意思,事件就表明了一件事或一个动做,浏览器中的事件有哪些node

window事件 form事件 keyboard事件 mouse事件 media事件
afterprint onblur onkeydown onclick onabort
beforeprint onchange onkeypress ondbclick oncanplay
onload oncontextmenu onkeyup ondrag oncanplaythrough
onunload onformchange ongragend ondurationchange
onbeforeunload onforminput ondragenter onemptied
onerror onforcus ondragleave onended
onhaschange oninput ondragover onerror
onmessage oninvalid ondragstart onloadeddata
onoffline onreset ondrop onloadedmetadata
ononline onselect onmousedown onloadstart
onpagehide onsubmit onmousemove onpause
onpageshow onmouseout onplay
onpopstate onmouseover onplaying
onredo onmouseover onprogress
onresize onmoseup onratechange
onstorage onmosewhell onreadystatechange
onundo onscroll onseeked
onunload onseeking
onstalled
onsuspend
ontimeupdate
onvolumechange
onwaiting

事件触发过程

从上面各方各面的事件上咱们能够看出浏览器冲加载到退出那一刻,无时不刻不在触发事件,那么事件触发是怎样的一个流程呢?编程

输入图片说明

当dom节点发生了某些操做时,就会有一个事件发射出去,这个事件从window发出,不断通过下级节点知道目标节点,这个阶段称为捕获阶段。全部通过的节点都会触发这个事件,捕获阶段的任务就是创建事件传递线路,以便后面冒泡阶段顺着该线路返回至window。监听该阶段的事件,能够经过把addEventListener第三个参数设为true浏览器

node.addEventListener('click', function() {}, true);

当事件传递到目标节点哪里,最终会在目标节点上触发这个事件,这个就是目标阶段(事件触发的目标老是最最底层的节点:如<p>hello <em>world</em></p>,目标节点能够是p也能够是em)网络

当事件到达目标节点以后,会沿捕获阶段的路线原路返回,这个阶段称为冒泡阶段,一样沿途全部的节点都会再次触发该事件。dom

监听父节点

由事件的触发机制咱们能够看到,沿途全部的父节点都会被触发两次该事件,一次是捕获阶段,一次是冒泡阶段。编程语言

node.addEventListener('click', functioon() {console.log('hello')}, true) ; //捕获阶段
node.addEventListener('click', function() {console.log('world')}, false); //冒泡阶段

因此咱们能够经过冒泡机制来监听父节点的事件,实现监听子节点,尤为是当子节点很是多的时候ide

注:因为IE浏览器不支持在捕获阶段监听事件,全部一般只用冒泡阶段来监听事件。函数

冒泡的烦恼

事件的冒泡机制,虽然很好,但有些场合并不使用。在比较复杂的应用中,监听比较复杂,咱们可能只但愿监听发生具体事件的节点,这个时候就要阻止冒泡spa

阻止冒泡可使用事件对象的stopPropagation方法

node.addEventListener('click', function(e) {
    //operations
    e.stopPropagation();    
}, false);

事件对象

在阻止冒泡时咱们使用到了事件对象,那么事件对象是什么? 当一个事件被触发的时候,会建立一个事件对象,这里面包含了一些有用的属性和方法,事件对象会做为回调函数的的第一个参数(如同node回调第一个参数永远是error同样)

<body>
  <div class="one">
    <div class="two">
      <div class="three">

      </div>
    </div>
  </div>
</body>

node.addEventListener('click', function(e) {
    console.log('事件对象', e)
}, false);

事件对象的属性和方法等(方法大部分上是对属性的get方法)

属性 描述 方法 描述
altKey addEventListener 添加事件绑定
bubbles 是否在冒泡阶段触发 removeEventListener 删除事件绑定
button stopPropagation 中止冒泡
buttons preventDefault 禁止浏览器默认行为
cancelBubble dispatchEvent 手动触发事件(var event=new Event('click'); element.dispatchEvent(event)
cancelable 是否能够调用proventDefault来禁止
clientX
clientY
composed
ctrlKey
currentTarget
defaultPrevented 是否禁止了默认行为
detail
eventPhase 当前事件触发在什么阶段。none:0;捕获:1;目标:2;冒泡:3
fromElement
isTrusted 浏览器触发(用户真实操做触发),仍是 JavaScript 代码触发的
layerX
layerY
metaKey
movementX
movementY
offsetX
offsetY
pageX 页面的坐标
pageY 页面的坐标
path 事件路径
relatedTarget
returnValue
screenX
screenY
shiftKey
sourceCapabilities
srcElement ie6-8 的触发事件的 dom 元素,非标准
target 触发的目标节点
timeStamp 返回事件发生时的时间戳
toElement
type 事件类型
view
which
x
y

事件代理

传统的事件绑定存在两个不足的地方:1)须要绑定不少个eventhandler 2)事件没法绑定后加入的节点。 事件的代理或委托就是事件触发过程当中冒泡机制和事件对象的应用,j简单的结构以下

document.getElementById("parent-list").addEventListener("click",function(e) {
	// e.target是被点击的元素!
	// 若是被点击的是li元素
	if(e.target && e.target.nodeName == "li") {
		// 找到目标,输出ID!
		console.log("find");
	}
});
相关文章
相关标签/搜索