JS事件冒泡、捕获、委托

380 阅读4分钟

前端面试必考点:“JS事件冒泡、捕获、委托”

鉴于在面试之时JS事件冒泡、捕获、委托是必问核心点,因此在这里将梳理一遍这几个事件。

在了解事件冒泡、捕获、委托前我们先了解一下什么是事件,何为事件?

都知道浏览器将代码显示在前台,用户通过一些动作页面发生变化就是靠事件驱动的,根据用户触发不同的事件,根据事件执行相应的操作。我们日常所见的事件有“鼠标事件”、“键盘事件”、“页面事件”等等。

简单来说事件就是: 满足条件后,会去执行某一段代码的过程。

事件举例:

鼠标事件:onclick(鼠标单击事件)、dblclick(双击事件)mousedown(按下鼠标键时触发)、mouseup(释放按下的鼠标键时触发)、mousemove(鼠标移动事件)、mouseover(鼠标移入事件)等

键盘事件:keydown(按下键盘时触发)、keypress(按下有值的键时触发)、keyup(松开键盘时触发该事件)等

页面事件:scroll(滚动)、select(选中)、focus(获取焦)、blur(失去焦点)等

在之前的博客中提到过DOM树,由DOM树可以看出来,HTML中的任意一个元素都是DOM树中的一份子,当其中一个元素产生了一个事件时,它会按着一层层的传递到根节点,路上经过的所有节点都会收到这个事件,这个传播过程被称为事件流

DOM事件流分为两种分别是:冒泡事件和捕获事件

一、冒泡事件。

百度百科官方解释为:

简单说就是从发生事件的标签沿着DOM树开始向上查找,如果父元素也有这个事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素同理。直到document或window,冒泡结束。

用代码解释一下冒泡

<body>
	<div id="d1">
		中国
		<div id="d2">
			湖北
			<div id="d3">
				武汉
			</div>
		</div>
	</div>
	<script>
		function getid(can){
			return document.getElementById(can);
		}
		var d1 = getid("d1");
		var d2 = getid("d2");
		var d3 = getid("d3");
		d1.onclick = function(){
		    alert("中国")
		}
		d2.onclick = function(){
			alert("湖北")
		}
		d3.onclick = function(){
			alert("武汉")
		}
	</script>
</body>

如上代码,点击武汉框会依次触发onclick()弹出武汉==>湖北==>中国。当子代事件触发时,父代有相同事件时依次紧随其后的也触发事件。这就是冒泡

那么如果我只想要武汉弹出框呢?不想让它弹出武汉框后又继续弹出湖北和中国,这就可以用阻止事件冒泡

阻止事件冒泡

阻止事件冒泡有两种方法

方法一:event.stopPropagation( )

stopPropagation也是事件对象(Event)的一个方法,作用是阻止目标元素的冒泡事件,stopPropagation就是阻止目标元素的事件冒泡到父级元素。

	<script>
			function getid(can){
				return document.getElementById(can);
			}
			var d1 = getid("d1");
			var d2 = getid("d2");
			var d3 = getid("d3");
			d1.onclick = function(){
				alert("中国")
			}
			d2.onclick = function(){
				alert("湖北")
			}
			d3.onclick = function(){
				alert("武汉")
			}
             d2.onclick = function(e) {
                e = e || window.event
                if (e.stopPropagation) {
                    // 这里的e = 形参e
                    e.stopPropagation()
                } else { // IE9以下
                    // 这里的 e = window.event
                    // 阻止默认时间 true阻止;false不阻止
                    e.cancelBubble = true;
                }
            }
		</script>
</body>

如上,给武汉的父级元素湖北加了阻止事件冒泡方法,弹出结果便为“武汉”结束。

方法二:return false

这个方法比较暴力,他会同时阻止事件冒泡也会阻止默认事件;写上此代码,连接不会被打开,事件也不会传递到上一层的父元素;

	<script>
			function getid(can){
				return document.getElementById(can);
			}
			var d1 = getid("d1");
			var d2 = getid("d2");
			var d3 = getid("d3");
			d1.onclick = function(){
				alert("中国")
			}
			d2.onclick = function(){
				alert("湖北")
			}
			d3.onclick = function(){
				alert("武汉")
			}
             d2.onclick = function(e = e||window.e) {
               return false;
			}
		</script>
</body>

输出结果为武汉==>湖北,return false就是在默认找到这个元素时阻止它发生事件。

二、捕获型事件。

百度百科给予的官方解释:

简单说捕获事件与冒泡事件相反,是从document到触发事件的那个节点,即自上而下的去触发事件。

方法addEventListener(“”,function(){},false/true)
	//第一个参数是事件的名称
	//第二个参数是处理函数
	//第三个参数为冒泡/捕获      可选     默认为冒泡(false)            捕获(true)
	<div id="d1">
			中国
			<div id="d2">
				湖北
				<div id="d3">
					武汉
				</div>
			</div>
		</div>
		<script>
			function getid(can){
				return document.getElementById(can);
			}
			var d1 = getid("d1");
			var d2 = getid("d2");
			var d3 = getid("d3");
            d1.addEventListener("click",function(){
                alert("中国")
            },true)

            d2.addEventListener("click",function(){
                alert("湖北")
            },false)
            d3.addEventListener("click",function(){
                alert("武汉")
            },true)
    </script>
</body>

如上,给武汉和中国是一个true捕获,则按中国==>武汉==>湖北,因为湖北给的是false冒泡。

三、事件代理(委托)

事件委托是利用事件的冒泡原理来实现的,比如我们平时在给ul中的li添加事件的时候,我们都是通过for循环一个个添加,如果li很多个的话,其实就有点占内存了,这个时候可以用 事件代理来优化性能,如下:

<body>
		<ul>
			<li>1</li>
			<li>2</li>
			<li>3</li>
			<li>4</li>
			<li>5</li>
			<li>6</li>
			<li>7</li>
			<li>8</li>
			<li>9</li>
			<li>10</li>
			<li>11</li>
			<li>12</li>
			<li>13</li>
			<li>14</li>
			<li>15</li>
		</ul>
		<script>
			var ul = document.getElementsByTagName("ul")[0];
			ul.onclick = function(event){
				var event = event || window.event;
				var target = event.target || event.srcElement;
				console.log(target.innerHTML)
			}

		</script>
	</body>

事件委托说到底就是自己的事情给父元素干,利用好事件委托就可以极大地减少代码量。提高代码运行速率。