事件流

215 阅读4分钟

事件流是什么

参考文章

事件流是网页元素接收事件的顺序,"DOM2级事件"规定的事件流包括三个阶段:

事件捕获阶段、处于目标阶段、事件冒泡阶段。

(1)捕获阶段:事件从window对象自上而下向目标节点传播的阶段;

(2)目标阶段:真正的目标节点正在处理事件的阶段;

(3)冒泡阶段:事件从目标节点自下而上向window对象传播的阶段。

  • IE9以下的IE浏览器使用的是事件冒泡,先从具体的接收元素,然后逐步向上传播到不具体的元素。

  • Netscapte采用的是事件捕获,先由不具体的元素接收事件,最具体的节点最后才接收到事件。

  • 而W3C制定的Web标准中,是同时采用了两种方案,事件捕获和事件冒泡都可以。

事件冒泡:事件开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点或文档。

事件捕获:事件开始由不太具体的节点接收,然后逐级向下传播到最具体的节点。它与事件冒泡是个相反的过程。

首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是时间冒泡阶段,可以在这个阶段对事件做出响应。

虽然捕获阶段在规范中规定不允许响应事件,但是实际上还是会执行,所以有两次机会获取到目标对象。

事件绑定

事件绑定分为DOM0级(on+type)DOM2级(addEventListener)

1. DOM0级

<div id="box1">
	<div id="box2">
		<div id="box3"></div>
	</div>
</div>
box1.onclick = function(){
	console.log('box1');
}
box2.onclick = function(){
	console.log('box2');
}
box3.onclick = function(){
	console.log('box3');
}

此时点击box3,依次弹出:box3 box2 box1

这就是事件冒泡

DOM0级事件处理程序的缺点在于一个处理程序「事件」无法同时绑定多个处理函数,比如在一个按钮上添加多个点击事件。

2. DOM2级

DOM2级事件在DOM0级事件的基础上弥补了一个处理程序无法同时绑定多个处理函数的缺点,允许给一个处理程序添加多个处理函数。也就是说,使用DOM2事件可以随意添加多个处理函数,移除DOM2事件要用removeEventListener。

true捕获,false冒泡。

<div id="box1">
	<div id="box2">
		<div id="box3"></div>
	</div>
</div>
box1.addEventListener('click', function(){
	console.log('box1');
},true);
box2.addEventListener('click', function(){
	console.log('box2');
},true);
box3.addEventListener('click', function(){
	console.log('box3');
},true);

此时弹出顺序从1-3,这就是事件捕获

注: IE8级以下版本不支持addEventListener和removeEventListener,需要用attachEvent和detachEvent来实现:

// IE8级以下版本只支持冒泡型事件,不支持事件捕获所以没有第三个参数
// 方法中包含2个参数,分别是绑定的事件处理属性名称(不包含on)、事件处理函数
btn.attachEvent('onclick', fn); // 绑定事件 
btn.detachEvent('onclick', fn); // 解绑事件 

阻止事件冒泡兼容

不支持冒泡的事件:blur、focus、mouseenter、mouseleave等。

box1.onclick = function (){
	console.log('box1')
}
box2.onclick = function (){
	console.log('box2')
}
box3.onclick = function (e){
	e.stopPropagation();
	console.log('box3')
}
function stopPropagate(e){
	var event = e || window.event;
	if(event.stopPropagation){
		event.stopPropagation();
	}else if(event.cancelBubble){ //IE
		event.cancelBubble = true;
	}
}

阻止默认事件兼容

function preventDef(e){
	var g = e || window.event;
	if(g.preventDefault){
		g.preventDefault();
	}else if(g.returnValue){
		g.returnValue = false;
	}
	return false;
}

其余DOM事件(DOM3级事件)

DOM3级事件在DOM2级事件的基础上添加了更多的事件类型,全部类型如下:

  1. UI事件,当用户与页面上的元素交互时触发,如:load、scroll
  2. 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
  3. 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup
  4. 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
  5. 文本事件,当在文档中输入文本时触发,如:textInput
  6. 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
  7. 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart
  8. 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified

同时DOM3级事件也允许使用者自定义一些事件

事件委托

ul->li事件委托举例:

ul.onclick = function (e){
	console.log(e.target);
}
  • 优点:

    • 可以大量节省内存占用,减少事件注册。
    • 可以实现当新增子对象时,无需再对其进行事件绑定,对于动态内容部分尤为合适
  • 缺点:

    • 事件代理的常用应用应该仅限于上述需求,如果把所有事件都用事件代理,可能会出现事件误判。即本不该被触发的事件被绑定上了事件。