事件响应链

106 阅读3分钟

事件源

事件源:触发事件的元素,单击某个子元素时,该元素称为事件源;单击事件不仅发生在事件源上,也发生在其文档树上的所有的父级元素上。

事件捕获

事件捕获:结构上(非视觉上)嵌套关系的元素,会存在事件捕获的功能,即同一事件,自父元素捕获至子元素(事件源元素)。自顶向下即父级 → 子级。事件先从window对象,然后再到document(对象),然后是html标签(通过document.documentElement获取html标签),然后是body标签(通过document.body获取body标签),然后按照普通的html结构一层一层往下传,最后到达目标元素。

事件冒泡

事件冒泡:结构上(非视觉上)嵌套关系的元素,会存在事件冒泡的功能,即同一事件,自子元素冒泡向父元素。自底向上即子级 → 父级

事件流

事件流对应着事件的触发顺序

1.事件流的三个阶段:先捕获,后目标,再冒泡,只能有一个阶段触发事件处理程序的执行,即捕获阶段触发了到了冒泡阶段就不再触发。

2.当事件经过所有元素都没有被处理,这个事件消失

3.事件传递的过程,只跟文档树的结构有关系(html中标签嵌套关系的元素有关)跟界面显示的层叠效果没有任何关系(标签设置了定位脱离文档流的元素无关)

事件响应链

QQ图片20220720125759.png

对于事件的目标元素(事件源)捕获和冒泡是相同的

    <style>
        body{
            margin: 0px;
        }
        .box1 {
            width: 400px;
            height: 300px;
            background-color: brown;
            cursor: pointer;
            position: relative;
            left: 100px;
            top: 20px;
        }
        .box2{
            width: 200px;
            height: 200px;
            background-color: red;
            cursor: pointer;
            position: absolute;
            left: 10px;
            top: 20px;
        }
        .box3{
            width: 100px;
            height: 100px;
            background-color: gold;
            cursor: pointer;
            margin: 10px;
            padding: 5px;
            border: 3px solid saddlebrown;
        }
    </style>
    <div class='box1'>
        <div class="box2">
             <div class="box3">
                 
             </div>
        </div>
    </div>
    <script>
        let box1=document.querySelector(".box1")
        let box2=document.querySelector(".box2")
        let box3=document.querySelector(".box3")
        box1.addEventListener("click",(e)=>{
            console.log("box111111111a",e.target)
        });
    </script>

image.png

三次点击的事件源不同,但是给父级元素绑定的事件点击子元素也会触发。

    <style>
        body{
            margin: 0px;
        }
        .box1 {
            width: 400px;
            height: 300px;
            background-color: brown;
            cursor: pointer;
            position: relative;
            left: 100px;
            top: 20px;
        }
        .box2{
            width: 200px;
            height: 200px;
            background-color: red;
            cursor: pointer;
            position: absolute;
            left: 450px;
            top: 20px;
        }
        .box3{
            width: 100px;
            height: 100px;
            background-color: gold;
            cursor: pointer;
            margin: 10px;
            padding: 5px;
            border: 3px solid saddlebrown;
        }
    </style>
    <div class='box1'>
        <div class="box2">
             <div class="box3">
                 
             </div>
        </div>
    </div>
    <script>
        let box1=document.querySelector(".box1")
        let box2=document.querySelector(".box2")
        let box3=document.querySelector(".box3")
        box1.addEventListener("click",(e)=>{
            console.log("box111111111a",e.target)
        });

image.png

对于脱离了文档流的子元素,当事件源是子元素时同样会触发父元素的事件。

    <style>
        body{
            margin: 0px;
        }
        .box1 {
            width: 400px;
            height: 300px;
            background-color: brown;
            cursor: pointer;
            position: relative;
            left: 100px;
            top: 20px;
        }
        .box2{
            width: 200px;
            height: 200px;
            background-color: red;
            cursor: pointer;
            position: absolute;
            left: 450px;
            top: 20px;
        }
        .box3{
            width: 100px;
            height: 100px;
            background-color: gold;
            cursor: pointer;
            margin: 10px;
            padding: 5px;
            border: 3px solid saddlebrown;
        }
    </style>
    <div class='box1'>
        <div class="box2">
             <div class="box3">
                 
             </div>
        </div>
    </div>
    <script>
        let box1=document.querySelector(".box1")
        let box2=document.querySelector(".box2")
        let box3=document.querySelector(".box3")
        box1.addEventListener("click",(e)=>{
            console.log("box111111111a",e.target)
        });
        box2.addEventListener("click",(e)=>{
            console.log("box222222b",e.target)
        });
        box3.addEventListener("click",(e)=>{
            console.log("box33333c",e.target)
        });
    </script>

image.png

当点击最后一个子元素时,会先执行最后一个子元素的事件,再冒泡执行父级元素绑定的事件但冒泡运行的是与子元素触发的事件为同一类型的事件

addEventListener绑定事件第3个参数

默认传统绑定的事件基本上都是冒泡阶段触发,但addEventListener绑定事件可以通过第3个参数修改。

addEventListener绑定事件,如果把第3个参数设置为true,则在捕获的时候执行事件处理函数,不传参默认为false。true捕获阶段触发 ,false冒泡阶段触发

    <style>
        body{
            margin: 0px;
        }
        .box1 {
            width: 400px;
            height: 300px;
            background-color: brown;
            cursor: pointer;
            position: relative;
            left: 100px;
            top: 20px;
        }
        .box2{
            width: 200px;
            height: 200px;
            background-color: red;
            cursor: pointer;
            position: absolute;
            left: 450px;
            top: 20px;
        }
        .box3{
            width: 100px;
            height: 100px;
            background-color: gold;
            cursor: pointer;
            margin: 10px;
            padding: 5px;
            border: 3px solid saddlebrown;
        }
    </style>
    <div class='box1'>
        <div class="box2">
             <div class="box3">
                 
             </div>
        </div>
    </div>
    <script>
        let box1=document.querySelector(".box1")
        let box2=document.querySelector(".box2")
        let box3=document.querySelector(".box3")
        box1.addEventListener("click",(e)=>{
            console.log("box111111111a",e.target)
        },true);
        box2.addEventListener("click",(e)=>{
            console.log("box222222b",e.target)
        });
        box3.addEventListener("click",(e)=>{
            console.log("box33333c",e.target)
        });
    </script>

image.png

设置为true,捕获阶段触发,当点击最后一个子元素时,捕获阶段时就会先触发绑定在父级元素的同一类型的事件。

    <style>
        body{
            margin: 0px;
        }
        .box1 {
            width: 400px;
            height: 300px;
            background-color: brown;
            cursor: pointer;
            position: relative;
            left: 100px;
            top: 20px;
        }
        .box2{
            width: 200px;
            height: 200px;
            background-color: red;
            cursor: pointer;
            position: absolute;
            left: 450px;
            top: 20px;
        }
        .box3{
            width: 100px;
            height: 100px;
            background-color: gold;
            cursor: pointer;
            margin: 10px;
            padding: 5px;
            border: 3px solid saddlebrown;
        }
    </style>
    <div class='box1'>
        <div class="box2">
             <div class="box3">
                 
             </div>
        </div>
    </div>
    <script>
        let box1=document.querySelector(".box1")
        let box2=document.querySelector(".box2")
        let box3=document.querySelector(".box3")
        box1.addEventListener("click",(e)=>{
            console.log("box111111111捕获阶段触发的",e.target);
            console.log(e.path,"AOTU22");
        },true);
        box1.addEventListener("click",(e)=>{
            console.log("box11111冒泡阶段触发的",e.target);
            console.log(e.path,"AOTU33");
        });
        box3.addEventListener("click",(e)=>{
            console.log("box33333c",e.target)
            console.log(e.path,"AOTU11");
        });
    </script>

image.png

此时相当于给父级元素绑定了两个事件,一个在捕获阶段触发,一个在冒泡阶段触发。

事件对象的path属性表示事件经过的对象

一些事件冒泡的总结

load:不冒泡

scroll:不冒泡

焦点事件:

blur:不冒泡(因为失去焦点本身就是针对这个元素的)

focus:不冒泡(因为获取焦点本身就是针对这个元素的)

focusin:focus的冒泡版

focusout:blur的冒泡版

鼠标事件

click:冒泡

dblclick:冒泡

mousedown:冒泡

mouseenter:不冒泡

mouseleave:不冒泡

mousemove:冒泡

mouseout:冒泡

mouseover:冒泡

mouseup:冒泡

键盘事件

keydown:冒泡

keypress:冒泡

keyup:冒泡