Js 事件原理与事件委托

举报
bafeitu 发表于 2020/04/18 20:09:50 2020/04/18
【摘要】 事件原理三阶段捕获(有外向内)、目标、冒泡(由内向外)事件冒泡(eventbubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。即子标签发生事件后,向父级发送该事件,一直追溯到document。如:点击一个嵌套在body中的button,则该button的onclick事件也会传递给body、docume...

事件原理三阶段

捕获(有外向内)、目标、冒泡(由内向外)

事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。即子标签发生事件后,向父级发送该事件,一直追溯到document。如:点击一个嵌套在 body中的button,则该button的onclick事件也会传递给body、document中,触发他们的onclick里触发的函数。

案例

  <style>    
div{    
position: absolute;    
left:0;    
right:0;    
top:0;    
bottom:0;    
}    
.div0    
{    
width: 200px;    
height: 200px;    
background-color: skyblue;    
margin: auto;    
}    
.div1{    
width: 100px;    
height: 100px;    
background-color: yellowgreen;    
margin: auto;    
}    
.div2{    
width: 50px;    
height: 50px;    
background-color: orange;    
margin: auto;    
}    
</style>    
</head>    
<body>    
<div class="div0">    
<div class="div1">    
<div class="div2"></div>    
</div>    
</div>    
<script>    
div0.addEventListener("click",clickHandler0);    
div1.addEventListener("click",clickHandler1);    
div2.addEventListener("click",clickHandler2);    
function clickHandler0(e){    
console.log("点击div0")    
}    
function clickHandler1(e){    
console.log("点击div1")    
}    
</script>

三阶段原理过程:

阻止事件冒泡

当对子元素添加了事件侦听后,执行的时候会触发父元素相同类型的事件,此时需要阻止事件冒泡。
早期IE是没有捕获阶段的,只有冒泡,cancelBubble为阻止冒泡。后来的stopPropagaiton,既有阻止冒泡的功能,也有阻止捕获的功能,但如果译为阻止传播,那么跟cancel就是两个东西了,所以还是叫做阻止冒泡。阻止事件冒泡(传播)的方法是:

  • e.stopPropagation();通用

  • e.cancelBubble=true;仅适用在IE8及以下

<script>

    div0.addEventListener("click",clickHandler0,true);//开启捕获时就执行
    div1.addEventListener("click",clickHandler1);
    div2.addEventListener("click",clickHandler2,true);//开启捕获时就执行

    function clickHandler2(e){
        console.log("点击div2")
        // console.log(e);
        // 停止冒泡,后面的就不会冒泡了
        e.stopPropagation();
        // 仅适用在IE8及以下
        // e.cancelBubble=true;

    } 
/script>

iv0.addEventListener(事件类型,事件回调函数,是否捕获时执行);
事件类型 必须是字符串,可以设置为任意字符串,但是部分字符串是系统事件类型
事件回调函数 指向一个函数,当收到事件时执行该函数,如果没有收到不执行函数,写侦听事件时不执行函数
是否捕获时执行 默认值是false,在冒泡时执行,捕获时不执行,

点击div2发现执行顺序发生改变

事件委托

事件侦听添加(注册事件)占有内存的,尽量减少事件侦听的数量,将子元素的事件委托给父元素来执行,叫做事件委托。
当删除对象时,一定要将对象上的侦听事件移除,否则会造成内存泄露。
应用于:在多个元素进行侦听事件中,如果这些元素有容器嵌套关系,就需要考虑阻止冒泡。
当多个元素需要侦听事件时,可以给这些元素的父容器增加事件,达到侦听所有元素,即是事件委托效果。
案例:点击 li ,让其子元素 ul 切换显示。

<body>
<ul id="skils">
<li>H5
    <ul>
        <li>JS
            <ul>
            <li>原生</li>
                <li>框架
                    <ul>
                        <li>VUEJs</li>
                        <li>ReactJs</li>
                        <li>AngularJs</li>
                    </ul>
                </li>
            <li>App</li>
            <li>小程序</li>
            <li>网页开发</li>
            </ul>
        </li>
    </ul>
</li>
<li>JAVA</li>
<li>PHP</li>
<li>LINUX</li>
<li>PYTHON</li>
</ul>					
<script>
        //把子元素的侦听事件全部委托给最外层的父元素,叫做事件委托

	init();

	function init(){
		var skils = document.getElementById("skils");
		//给父元素添加侦听事件
		skils.addEventListener("click",clickHandler);
	}

	function clickHandler(e){
		//e.target 事件的目标 真实点击到最终的目标对象
		//阻止冒泡,到此就结束,不再冒泡
		e.stopPropagation();
		//判断点击目标的节点名是不是“LI” ,不是就不执行 
		if(e.target.nodeName !== "LI") return;
		//判断点击目标有没有子元素
		if(e.target.firstElementChild){
			// 设置开关,显示和隐藏ul
			// 第一次默认是隐藏
			if(!e.target.bool){
				e.target.firstElementChild.style.display = "none";
			}else{
				e.target.firstElementChild.style.display = "block";
			}
			//点击完后将e.target.bool 取反,进行显示操作
			e.target.bool = !e.target.bool;
			}
		}
        </script>
</body>

扩展:

  • e.currentTarget 是事件侦听事件对象(什么对象执行addEventListener函数就是谁)

  • e.target 事件的目标对象 真实点击的最终目标对象

  • e.srcElement 事件的目标对象,兼容IE

  • 事件函数中this默认等同于e.currentTarget,都是事件侦听的对象

文章来源: www.cnblogs.com,作者:码上出彩,版权归原作者所有,如需转载,请联系作者。

原文链接:https://www.cnblogs.com/my12-28/p/12725880.html

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。