JavaScript--事件的冒泡和捕获以及事件委托

185 阅读3分钟

事件的捕获和事件的冒泡

作用

其实他们的作用都是一样的:决定我们事件执行的先后顺序。只不过这两种规则完全是一个逆过程

介绍

  • 事件的捕获由网景公司提出,他指出事件执行的顺序应该是由外到内的过程:document->html->body->dom
  • 事件的的冒泡由微软公司提出,他指出事件的执行顺序应该是由内到外冒泡的过程:dom->body->html->document

两种方式吵得不可开交,最终,w3c采取了一种折中的方式:事件触发的顺序:先捕获后冒泡。这也符合我们的认知习惯,从外到内,再从内到外。但是事件只能选择在捕获阶段触发,还是在冒泡阶段触发。
事件默认情况下,是在冒泡过程中触发的。

addEventListener()方法的第三个参数就是一个bool值,决定我监听的事件是在捕获阶段触发true,还是在冒泡阶段触发false 默认值为true

小思考:
当一个元素绑定了若干个事件那么他的执行顺序是怎样的呢?比如div1绑定了两个click事件,一个是在冒泡过程执行。一个是在捕获阶段执行。那么哪个先执行呢?分两种情况

  1. div1不是目标元素,而是路过的元素。
    相对简单一点,在捕获阶段执行捕获阶段的click事件,然后再在冒泡过程执行冒泡阶段的click事件。

  2. div1是目标元素。
    这时候就是谁先绑定谁先执行。

tips:几乎所有事件都有冒泡过程,但是focus没有。

如何阻止事件的冒泡

event.stopPropagation()
eaxmple: 代码:

						<div class="aaa">
							
						</div>
			</div>
<script>
	document.getElementsByTagName("div")[0].addEventListener("click",function(){console.log(1);});
		document.getElementsByTagName("div")[1].addEventListener("click",function(event){console.log(2);event.stopPropagation();});
	</script>

直接在子代div的click事件里面阻止冒泡即可,他就不会继续传播点击事件。

事件委托机制

事件委托的原理

其实就是利用事件冒泡机制,事件可以逐级向上传播的特点,从而实现把事件委托给上级元素来处理。

为什么要进行事件委托

  1. 拿ul和li来举例,如果我需要实现一个点击li标签从而打印li标签的内容的需求,那么我得给每一个li标签都绑定一个click事件,从而来实现需求,但是如果我们的li元素特别的多,那么我们的js代码就会显得特别的臃肿且重复,储存起来也耗费内存,并且给这么多元素绑定事件,那么会导致页面性能下降。我们完全可以把这个click事件委托给ul来实现。这样我们只需要定义一个click事件就可以达到目的。

事件委托的实现关键

我个人觉得是这个event.target对象,他代表你当前点击的这个DOM元素,ie中这个对象应该是event.srcElement

example

<ul>
		<li>1</li>
		<li>2</li>
		<li>3</li>
	</ul>
	<script>
		var ul = document.getElementsByTagName("ul")[0];
		ul.addEventListener("click",function(e){
			var e = e.target||e.srcElement;//兼容性
			if(e.nodeName.toLowerCase()=="li")//排除没有点到li标签的情况
			{
				console.log(e.innerHTML);
			}
			
		})
	</script>

小思考

如果li元素并不是一个简单的li元素,他还有很多子元素那么这时候该怎么处理呢? 写个循环就可以解决了。

	<script>
		var ul = document.getElementsByTagName("ul")[0];
		ul.addEventListener("click",function(e){
			var e = e.target||e.srcElement;//兼容性
            while(e.nodeName.toLowerCase()!="ul")
            {
            if(e.nodeName.toLowerCase()=="li")
            {
            console.log(e.innerHTML);
            break;
            }
            else
            {
           	e=e.parentNode;
            }
            }
			
			
		})
	</script>