欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript 事件处理机制(事件模型)

程序员文章站 2022-05-05 22:57:33
...

DOM是树形结构,如果父子节点都绑定事件,事件处理先后的顺序如何决定?
这就涉及到事件流的概念:

一、事件流

事件流指的是从页面中接受事件的顺序。

事件冒泡

事件冒泡是一种从下往上的传播方式,事件由文档中嵌套层次最深的节点逐渐传播到高层父节点。

事件捕获

事件捕获流处理事件的顺序与事件冒泡相反。
JavaScript事件处理程序遵循先捕获(父节点先发现事件)后冒泡(从子节点向上传递)的规则。 如下图所示:
JavaScript 事件处理机制(事件模型)

二、DOM0事件模型

以鼠标点击事件为例,以下代码在两个div上分别定义了鼠标点击事件,这种事件的定义方式为DOM0事件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript事件流</title>
    <style>
        #out{
            width: 200px;
            height: 200px;
            background-color: blue;
        }
        #in{
            width: 100px;
            height: 100px;
            background-color: blueviolet;
        }
    </style>
</head>
<body>
    <div id="out">
        <div id="in">
        </div>
    </div>
    <script>
        var outer = document.getElementById("out");
        var inner = document.getElementById("in");
        outer.onclick = function () {
            console.log("点击了外部div");
        };
        inner.onclick = function () {
            console.log("点击了内部div");
        }
    </script>
</body>
</html>

当点击内部div时,控制台输出的顺序为:
JavaScript 事件处理机制(事件模型)
由此可见,对于DOM0级事件,浏览器是在冒泡阶段对触发的事件进行响应的。
此外对于DOM0级事件来说,同一元素的某一事件只能注册一个,后边注册的同种事件会覆盖之前注册的事件。正是因为这个特点,要想解除某一元素注册的DOM0级事件,只需要再将其事件注册为null即可。例如,要想解除以上代码中外部div的鼠标点击事件,只需要在后面加上一句以下代码即可:

outer.onclick = null;

三、DOM2事件模型

修改以上注册事件的方式即可定义DOM2级事件:

var outer = document.getElementById("out");
var inner = document.getElementById("in");
outer.addEventListener("click", function (e) {
    console.log("点击了外部div(DOM2级事件)");
}, false);
outer.addEventListener("click", function (e) {
    console.log("点击了外部div(DOM2级事件——第二个点击事件)");
}, false);
inner.addEventListener("click", function (e) {
    console.log("点击了内部div(DOM2级事件)");
}, false);

通过addEventListener方法注册的事件称为DOM2级事件,该方法一共接收3个参数:

  • 第一个参数:注册的事件类型(注意前面没有on)
  • 第二个参数:回调函数,即事件响应方法
  • 第三个参数:true/false,代表是否捕获,若设置为true,代表在事件捕获阶段触发事件;若设置为false,代表在事件冒泡阶段触发事件。一般情况下该参数均设置为false。

在修改了事件模型之后,点击内部div时控制台显示的消息为:
JavaScript 事件处理机制(事件模型)
因为设置了事件冒泡,所以浏览器按照事件冒泡的顺序处理事件:先触发内部div点击事件,再触发外部div点击事件。可以看到,不同于DOM0级事件,DOM2级事件允许为同一元素注册多个同类事件。
当将以上addEventListener函数的第三个参数均改为true(启用捕获)时,控制台输出的消息顺序变为:
JavaScript 事件处理机制(事件模型)
由于父节点先被捕获,所以首先触发了外部div的事件。
在DOM2级事件中,由于后注册的事件不会覆盖之前注册的事件,所以不能通过将元素事件注册为null的方式来解除事件。在DOM2级事件模型中,要想解除事件,需要调用removeEventListener函数,该函数的参数与addEventListener方法的参数完全一致,用于解除注册的DOM2级事件。这里需要注意的是,要想解除某一事件,必须把回调函数先保存起来,匿名函数无法移除

阻止冒泡

有的时候,当点击了内部div后,我们只希望触发内部div的点击方法,不希望触发外部div的点击方法,这时候就要用到阻止冒泡。
阻止冒泡的方法很简单,只要在内部div的点击方法中添加一行代码就可以实现阻止冒泡:

inner.addEventListener("click", function (e) {
    console.log("点击了内部div(DOM2级事件)");
    e.stopPropagation();  // 阻止冒泡
}, false);

阻止冒泡后,点击内部div时,控制台将不再输出外部div的点击消息:
JavaScript 事件处理机制(事件模型)

相关标签: 前端 javascript