首页 > 编程笔记 > JavaScript笔记 阅读:1

jQuery事件冒泡和事件捕获详解(附带实例)

事件捕获与事件冒泡都是一种事件模型,DOM 标准规定应该同时使用这两个模型:首先事件要从 DOM 树顶层的元素到 DOM 树底层的元素进行捕获,然后通过事件冒泡返回到 DOM 树的顶层。

在标准事件模型中,事件处理程序既可以注册在事件捕获阶段,也可以注册在事件冒泡阶段。但是并不是所有的浏览器都支持标准事件模型,大部分浏览器默认把事件处理程序注册在事件冒泡阶段,所以 jQuery 始终会在事件冒泡阶段注册事件处理程序。

什么是事件捕获与事件冒泡

下面我们就通过一个实例来展示什么是事件冒泡、什么是事件捕获以及事件冒泡与事件捕获的区别。

【实例 1】通过一个生动形象的页面结构展示事件冒泡模型。
1) 创建一个名为 index.html 的文件,在该文件的 <head> 标记中使用下面的语句引入 jQuery 库。
<script type="text/javascript" src="../js/jquery-3.6.4.min.js"></script>

2) 在下面的页面结构中,<span> 是 <p> 的子元素,而 <p> 又是 <div> 的子元素:
<body>
  <div class="test1">
    <b>div元素</b>
    <p class="test2">
      <b>p元素</b>
      <span><b>span元素</b></span>
    </p>
  </div>
</body>

3) 为元素添加 CSS 样式,这样就能更清楚地了解页面的层次结构:
<style type="text/css">
    .redBorder {
      border: 1px solid red;
    }
    .test1 {
      /* <div>元素的样式 */
      width: 240px;
      height: 150px;
      background-color: #cef;
      text-align: center;
    }
    .test2 {
      /* <p>元素的样式 */
      width: 160px;
      height: 100px;
      background-color: #ced;
      text-align: center;
      line-height: 20px;
      margin: 10px auto;
    }
    span {
      /* <span>元素的样式 */
      width: 100px;
      height: 35px;
      background-color: #fff;
      padding: 20px 20px 20px 20px;
    }
    body {
      font-size: 12px;
    }
</style>
页面结构如下图所示:


图 1 页面结构

4) 为这 3 个元素添加 mouseout 和 mouseover 事件,当鼠标指针在元素上悬停时为元素加上红色边框,当鼠标指针从元素上移出时移除红色边框。如果鼠标指针悬停在 <span> 元素上,会不会触发 <p> 元素和 <div> 元素的 mouseover 事件呢?毕竟此时鼠标指针悬停在这 3 个元素上。

图 2~4 展示了鼠标指针悬停在不同元素上的效果。


图 2 鼠标指针悬停在<span>元素上的效果


图 3 鼠标指针悬停在<p>元素上的效果


图 4 鼠标指针悬停在<div>元素上的效果

从图 2~4 中可以看到,当鼠标指针悬停在 <span> 元素上时,3 个元素都被加上了红色边框。这说明在触发 <span> 元素的 mouseover 事件的同时,其他两个元素的 mouseover 事件也被响应。

在触发 <span> 元素的事件时,浏览器最先响应的是 <span> 元素的事件,其次是 <p> 元素的事件,最后是 <div> 元素的事件。

在浏览器中事件响应的顺序如下图所示:


图 5 事件冒泡(由具体到一般)

这种事件响应的顺序就叫事件冒泡。事件冒泡是从 DOM 树的顶层向下进行事件响应的。

另一种相反的顺序就叫事件捕获,事件捕获是从 DOM 树的底层向上进行事件响应的,事件捕获如下图所示。


图 6 事件捕获(由一般到具体)

事件对象

通常情况下,在不同浏览器中获取事件对象是比较困难的。针对这个问题,jQuery 进行了必要的处理,使得在任何浏览器中都能轻松地获取事件对象以及事件对象的一些属性。

在程序中使用事件对象是非常简单的,只要为函数添加一个参数即可。具体 jQuery 代码如下:
$("element").on("mouseout", function(event) {
    // event:事件对象
    // 省略部分代码
});
当单击 <element> 元素时,事件对象就被创建,该事件对象只有事件处理函数才可以访问。事件处理函数执行完毕后,事件对象就被销毁了。

阻止事件冒泡

事件冒泡经常会造成一些令开发人员头疼的问题,所以在必要的时候,需要阻止事件冒泡。

要阻止事件冒泡,就必须访问事件对象。事件对象提供了 stopPropagation() 方法,使用该方法可以阻止事件冒泡。

注意,stopPropagation() 方法只能阻止事件冒泡,它相当于在传统的 JavaScript 中操作原始的 event 事件对象的 event.cancelBubble=true 来阻止事件冒泡。

阻止例 1 中程序的事件冒泡,可以在每个事件处理程序中加入一行代码,例如:
$(".test1").on("mouseover", function(event) {
    $(".test1").addClass("redBorder");
    event.stopPropagation(); // 阻止事件冒泡
});
由于 stopPropagation() 方法是跨浏览器的,所以不必担心它的兼容性。

加入了阻止事件冒泡代码的例 1 中程序的运行效果如下图所示:


图 7 阻止事件冒泡后的效果

当鼠标指针悬停在 <span> 元素上时,只有 <span> 元素被加上了红色边框,说明只有 <span> 元素响应 mouseover 事件,程序成功阻止了事件冒泡。

阻止浏览器默认行为

网页中的元素有自己的默认行为,例如,在表单验证的时候,表单的某些内容没有通过验证,但是在单击提交按钮以后表单还会被提交。这时就需要阻止浏览器的默认行为。在 jQuery 中,使用 preventDefault() 方法可以阻止浏览器的默认行为。

在事件处理程序中加入如下代码就可以阻止浏览器默认行为:
event.preventDefault(); // 阻止浏览器默认行为
如果想同时阻止事件冒泡和浏览器默认行为,可以在事件处理程序中设置返回 false,即:
return false;  //阻止事件冒泡和浏览器默认行为
这是同时调用 stopPropagation() 和 preventDefault() 方法的一种简要写法。

【实例 2】阻止表单提交。
1) 创建一个名为 index.html 的文件,在该文件的 <head> 标记中使用下面的语句引入 jQuery 库。
<script type="text/javascript" src="../js/jquery-3.6.4.min.js"></script>

2) 在页面的 <body> 标记中创建一个表单,其中包含用户名文本框与注册按钮:
<form action="index.html" method="post">
    用户名:<input type="text" id="username"/><br/>
    <input type="submit" value="注册" id="subbtn"/>
</form>

3) 在引入 jQuery 库的代码下方编写 jQuery 代码,如果用户输入的用户名为空,则弹出提示信息并阻止表单提交:
$(document).ready(function() {
    $("#subbtn").on("click", function(event) {
        var username = $("#username").val();
        if (username == "") {
            alert("用户名不能为空!");
            $("#username").focus();
            event.preventDefault(); // 阻止表单提交的浏览器默认行为
        }
    });
});

可以将 event.preventDefault(); 改写为:
return false;

也可以将例 1 中阻止事件冒泡的如下代码:
event.stopPropagation();
改写为:
return false;

事件对象的属性

jQuery 中对事件对象的属性进行了封装,使得事件处理程序在各大浏览器下都可以正常运行而不需要对浏览器类型进行判断。下面介绍常用的事件对象的属性:

1) event.type

这个属性是用来获取事件类型的。例如以下代码:
$("a").click(function(event) {
    alert(event.type); // 获取事件类型
    return false;      // 阻止链接跳转
});
运行后会输出:

click

2) event.preventDefault() 和 event.stopPropagation()

这两个方法前面讲解过,在此不赘述。

3) event.target

event.target 的作用是获取触发事件的元素。jQuery 对其进行封装之后,避免了各大浏览器不同标准之间的差异。

4) event.relatedTarget

event.relatedTarget 属性返回与事件的目标节点相关的节点。

对于 mouseover 事件来说,该属性是鼠标指针移动到目标节点上时所离开的节点。

对于 mouseout 事件来说,该属性是鼠标指针离开目标节点时所进入的节点。

对于其他类型的事件来说,这个属性是没有用的。

5) event.pageX 和 event.pageY

这两个属性的作用是获取鼠标指针相对于页面的 x 坐标和 y 坐标。不使用 jQuery 时,在 IE 中使用 event.x 和 event.y,而在 Firefox 浏览器中使用 event.pageX 和 event.pageY。若页面中有滚动条,则要在属性中加上滚动条的宽度或高度。

【实例 3】Event对象。
1) 创建一个名为 index.html 的文件,在该文件的 <head> 标记中使用下面的语句引入 jQuery 库:
<script type="text/javascript" src="../js/jquery-3.6.4.min.js"></script>

2) 在页面的 <body> 标记中,创建一个 id 属性值为 ediv 的 <div> 元素,令它的文本内容为 "Event对象":
<div id="ediv">Event对象</div>

3) 在引入 jQuery 库的代码下方编写 jQuery 代码,当鼠标指针移动到 <div> 元素上时,弹出鼠标指针相对于页面的 x 坐标和 y 坐标:
$(document).ready(function() {
    $("#ediv").on("mouseover", function(event) {
        alert("当前鼠标指针的位置是:" + event.pageX + "," + event.pageY);
    });
});
运行本实例,效果如下图所示:


图 8 获取当前鼠标指针位置

6) event.which

该属性指示按下了哪个按键或按钮。按键既可以是鼠标的按键,也可以是键盘的按键。
$("a").on("mousedown", function(event) {
    alert(event.which); // 1为鼠标左键,2为鼠标中间键,3为鼠标右键
});

以下代码为获取键盘按键的代码:
$("input").on("keyup", function(event) {
    alert(event.which); // 获取键盘按键
});

相关文章