dom事件流

事件捕获(event capturing)

当使用事件捕获时javascript

| | ---------------| |----------------- | outer | | | | -----------| |----------- | | |inner \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------

outer上的事件处理器先触发, 而后是inner上的java

事件冒泡(event bubbling)

/ \
---------------| |----------------- | outer | | | | -----------| |----------- | | |inner | | | | | ------------------------- | | Event BUBBLING | -----------------------------------

与事件捕获相反, 当使用事件冒泡时, inner上的事件处理器先被触发, 其后是outer上面的。node

通常来讲事件冒泡机制,用的更多一些,因此在IE8以及以前,IE只支持事件冒泡。IE9+/FF/Chrome这2种模型都支持,能够经过addEventListener((type, listener, useCapture)的useCapture来设定,useCapture=false表明着事件冒泡,useCapture=true表明着采用事件捕获。默认是false,即事件冒泡。app

DOM事件流函数

DOM事件流:将事件分为三个阶段:捕获阶段、目标阶段、冒泡阶段。先调用捕获阶段的处理函数,其次调用目标阶段的处理函数,最后调用冒泡阶段的处理函数。ui

咱们在outC上触发onclick事件(这个是目标对象),若是咱们在outC上同时绑定捕获阶段/冒泡阶段事件处理函数会怎么样呢?this

<script>

 window.onload = function(){
 var outA = document.getElementById("outA"); 
 var outB = document.getElementById("outB"); 
 var outC = document.getElementById("outC"); 
 
 // 目标(自身触发事件,是冒泡仍是捕获无所谓)
 outC.addEventListener('click',function(){alert("target2");},true);
 outC.addEventListener('click',function(){alert("target1");},true);
 
 // 事件冒泡
 outA.addEventListener('click',function(){alert("bubble1");},false);
 outB.addEventListener('click',function(){alert("bubble2");},false);
 
 // 事件捕获
 outA.addEventListener('click',function(){alert("capture1");},true);
 outB.addEventListener('click',function(){alert("capture2");},true);

 
 
 };
 
</script>

<body>
 <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
 <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
  <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div> 
 </div>
 </div>
</body>

点击outC的时候,打印顺序是:capture1-->capture2-->target2-->target1-->bubble2-->bubble1。因为outC是咱们触发事件的目标对象,在outC上注册的事件处理函数,属于DOM事件流中的目标阶段。目标阶段函数的执行顺序:先注册的先执行,后注册的后执行。这就是上面咱们说的,在目标对象上绑定的函数是采用捕获,仍是采用冒泡,都没有什么关系,由于冒泡和捕获只是对父元素上的函数执行顺序有影响,对本身没有什么影响。若是不信,能够将下面的代码放进去验证。spa

// 目标(自身触发事件,是冒泡仍是捕获无所谓)
outC.addEventListener('click',function(){alert("target1");},false);
outC.addEventListener('click',function(){alert("target2");},true);
outC.addEventListener('click',function(){alert("target3");},true);
outC.addEventListener('click',function(){alert("target4");},false);

至此咱们能够给出事件函数执行顺序的结论了:捕获阶段的处理函数最早执行,其次是目标阶段的处理函数,最后是冒泡阶段的处理函数。目标阶段的处理函数,先注册的先执行,后注册的后执行。.net

阻止默认事件

1. 阻止冒泡事件代理

主要是用于阻止事件传播。阻止它被分派到其余的DOM节点上,在事件传播的任何阶段都能使用。使用方法以下(兼容IE):

function stopBubble(event){
	if(window.event){//兼容IE
		window.event.cancelBubble=true;
	}else{
		event.stopPropagation();
	}
 

2. 阻止默认事件

像submit这类的表单元素,都会绑定默认事件,若是不阻止默认事件,则绑定的其余方法也会无效。使用方法以下(兼容IE):

function stopDefaultEvent(event){
	if(window.event){//兼容IE
		window.event.returnValue=false;
	}else{
		event.preventDefault()
	}
	return false;
}

 

事件委托、时间代理

 

上面的例子是要阻止冒泡,有时候冒泡机制也能够被利用。先看一个问题:

假设要在页面上放在 10^n(n>=1) 个列表项元素,当我点击某个元素时,须要输出点击的是第几个。

通常作法是,遍历时给每一个元素绑定点击事件:

var li = document.getElementsByTagName('li'); for(var i=0; i<li.length; i++){ li[i].setAttribute('i',i+1); li[i].addEventListener('click', function(e){ var b = this.getAttribute('i'); console.log('这是第' + b + '个<li>元素'); }); } 

另外一种方法是,能够利用冒泡机制,在父元素只绑定一次点击事件:

var li = document.getElementsByTagName('li'); for(var i=0; i<li.length; i++){ li[i].setAttribute('i',i+1); } var ul = document.getElementById('wrapper'); ul.addEventListener('click', function(e){ if(e.target && e.target.nodeName.toUpperCase() === 'LI'){ var b = e.target.getAttribute('i'); console.log('这是第' + b + '个<li>元素'); } });

这种事件委托的方式减小了事件处理程序,也能下降程序的复杂性和出错几率。

参考:

https://www.jb51.net/article/94394.htm

https://blog.csdn.net/michael8512/article/details/77447537

相关文章
相关标签/搜索