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

本文深入讲解了前端浏览器中的事件机制,包括事件的触发过程、事件对象及其属性和方法,并介绍了如何利用事件冒泡机制实现事件代理。

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

什么事件

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

window事件form事件keyboard事件mouse事件media事件
afterprintonbluronkeydownonclickonabort
beforeprintonchangeonkeypressondbclickoncanplay
onloadoncontextmenuonkeyupondragoncanplaythrough
onunloadonformchangeongragendondurationchange
onbeforeunloadonforminputondragenteronemptied
onerroronforcusondragleaveonended
onhaschangeoninputondragoveronerror
onmessageoninvalidondragstartonloadeddata
onofflineonresetondroponloadedmetadata
ononlineonselectonmousedownonloadstart
onpagehideonsubmitonmousemoveonpause
onpageshowonmouseoutonplay
onpopstateonmouseoveronplaying
onredoonmouseoveronprogress
onresizeonmoseuponratechange
onstorageonmosewhellonreadystatechange
onundoonscrollonseeked
onunloadonseeking
onstalled
onsuspend
ontimeupdate
onvolumechange
onwaiting

事件触发过程

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

输入图片说明

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

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

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

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

监听父节点

由事件的触发机制我们可以看到,沿途所有的父节点都会被触发两次该事件,一次是捕获阶段,一次是冒泡阶段。

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

所以我们可以通过冒泡机制来监听父节点的事件,实现监听子节点,尤其是当子节点非常多的时候

注:由于IE浏览器不支持在捕获阶段监听事件,所有通常只用冒泡阶段来监听事件。

冒泡的烦恼

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

阻止冒泡可以使用事件对象的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方法)

属性描述方法描述
altKeyaddEventListener添加事件绑定
bubbles是否在冒泡阶段触发removeEventListener删除事件绑定
buttonstopPropagation停止冒泡
buttonspreventDefault禁止浏览器默认行为
cancelBubbledispatchEvent手动触发事件(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
srcElementie6-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");
	}
});

转载于:https://my.oschina.net/u/1249401/blog/805445

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值