JS事件

125 阅读2分钟

一、事件

JavaScript 与 HTML 的交互是通过事件实现的,事件代表文档或浏览器窗口中某个有意义的时刻.
事件意味着用户或浏览器执行的某种动作。比如,单击(click)、加载(load)、鼠标悬停.

二、DOM事件流

DOM2 Events 规范规定事件流分为 3 个阶段:事件捕获、到达目标和事件冒泡

image.png

事件捕获、事件冒泡

事件捕获的意思是最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件。
事件冒泡的意思是从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)

三、事件处理程序

HTML事件处理程序

<input type="button" value="Click Me" onclick="console.log('Clicked')"/>

DOM0事件处理程序

let btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log("Clicked");
};

DOM2事件处理程序


DOM2 Events 为事件处理程序的赋值和移除定义了两个方法:addEventListener()和 removeEventListener(),这两个方法暴露在所有 DOM 节点上,
它们接收 3 个参数:事件名、事件处理函数和一个布尔值,true 表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序。

仍以给按钮添加 click 事件处理程序为例
let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
console.log(this.id);
}, false);
};

用addEventListener实现事件捕获、事件冒泡

先看效果图,如果将事件处理函数注册在捕获阶段的话,点击“孙子”方块

image.png 如果将事件处理函数注册在冒泡阶段的话,点击“孙子”方块

image.png

注意!!!无论是事件冒泡还是事件捕获,一定要是一个事件,比如click事件 不能冒泡或者捕获mouseover事件 ```

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .d1 {
            width: 500px;
            height: 500px;
            background-color: gold;
        }
        .d2 {
            width: 400px;
            height: 400px;
            background-color: black;
        }
        .d3 {
            width: 300px;
            height: 300px;
            background-color: aliceblue;
        }
    </style>
</head>
<body>
<div class="d1">爸爸
    <div class="d2">儿子
        <div class="d3">孙子
        </div>
    </div>
</div>
<script>
    var d1 = document.getElementsByClassName('d1')[0];
    var d2 = document.getElementsByClassName('d2')[0];
    var d3 = document.getElementsByClassName('d3')[0];
    // 事件冒泡

    // d1.addEventListener('click', function(){
    //     console.log('d1')
    // }, false);
    // d2.addEventListener('click', function(){
    //     console.log('d2')
    // }, false);
    // d2.addEventListener('mouseover', function(){
    //     console.log('mouseover')
    // }, false);
    // d3.addEventListener('click', function(event){
    //     console.log('d3')
    //     event.stopPropagation() // 阻止事件冒泡
    // }, false);

    // 事件捕获
    d1.addEventListener('click', function(event){
        event.stopPropagation()
        console.log('爸爸')
    }, true);
    d2.addEventListener('click', function(){
        event.stopPropagation()
        console.log('儿子')
    }, true);
    d2.addEventListener('mouseover', function(){
        console.log('d2mouseover')
    }, true);
    d3.addEventListener('click', function(event){
        console.log('孙子')
    }, true);
    d3.addEventListener('mouseover', function(){
        console.log('d3mouseover')
    }, true);



</script>
</body>
</html>

为什么我们通常选择将事件处理函数注册在事件冒泡阶段而不是捕获阶段呢

1、出于主观考虑,我们触发一个dom元素的事件肯定是希望第一事件就看到这个事件的效果,而不是先让我的祖先元素、父元素他们的触发完,再去触发我想要的这个dom元素事件。
2、出于阻止行为考虑,如果注册在捕获阶段,那么我想阻止捕获行为就要由外到内一层一层的去给绑定事件加event.stopPropagation(), 直到我想要的这个dom元素事件为止。而如果注册在冒泡阶段,那么直接在dom元素事件上加event.stopPropagation()就行。