【每日一题NO.87】说说你对DOM事件流的理解

前端印记

共 3141字,需浏览 7分钟

 ·

2021-11-18 16:21

事件

JavaScriptHTML 之间的交互是通过事件实现的。
事件就是通过文档或浏览器窗口发生的一些特定的交互瞬间。
可以使用 监听器 (或者事件处理程序) 来预定事件,以便来执行相应的代码

事件流

描述的是页面中事件传播的顺序
事件发生的时候,会在元素节点之间按照特定的顺序传播,这个传播的过程叫做 DOM 的事件流
这个传播过程是:事件捕获 -- 事件目标 -- 事件冒泡
而早期的 IE 和 NetScape 提出了完全相反的事件流概念,IE 是事件冒泡,而 NetScape 的事件流就是事件捕获。

事件冒泡、事件捕获

  • IE 提出的事件流是事件冒泡,即从下到上,从目标触发的元素逐级往下向上传播,直到 window 对象。
  • 而 NetScape 的事件流就是事件捕获,即从 document 对象逐级向下传播到目标元素。由于 IE 低版本浏览器不支持,所以很少使用事件捕获。
  • 后来 ECMAScript 在 DOM2 中对事件流进行了进一步规范,基本上就是上述二者的结合,

DOM2 中事件规定的事件流包括三个阶段:

  1. 事件 捕获 阶段:事件从Document节点上 自上而下 向目标节点传播的阶段
  2. 处于目标阶段:真正的目标节点正在处理事件的阶段
  3. 事件 冒泡 阶段:事件从目标节点 自下而上 向Document传播的阶段
image

DOM 事件处理

DOM 节点增加了对事件处理,其分为四个级别

DOM0

DOM0 级事件具有极好的跨浏览器优势,会以最大的速度绑定

第一种方式是内联模型【行内模式】

<div onclick="btnClick()">clickdiv>
<script>
  function btnClick(){
    console.log("hello");
  }
script>

缺点是:不符合 W3C 中关于内容与行为分离的基本规范

第二种方式是脚本模式

<div id="btn">点击div>
<script>
  var btn=document.getElementById("btn");
  btn.onclick=function(){
    console.log("sunny");
  }
script>

但是会存在问题

<div id="btn">点击div>
<script>
  var btn=document.getElementById("btn");
  btn.onclick=function(){
    console.log("sunny");
  }
  btn.onclick=function(){
    console.log("sunny-sunny");
  }
script>

这个时候只能输出 sunny-sunny。很明显的是:

第一个事件函数被第二个事件函数给覆盖掉了,所以脚本模型的缺点就是:同一个节点只能添加一次同类型事件

<div id="btn3">
    btn3
    <div id="btn2">
        btn2
        <div id="btn1">
            btn1
        div>
    div>
div>
<script>
    let btn1 = document.getElementById("btn1");
    let btn2 = document.getElementById("btn2");
    let btn3 = document.getElementById("btn3");
    btn1.onclick=function(){
        console.log(1)
    }
    btn2.onclick=function(){
        console.log(2)
    }
    btn3.onclick=function(){
        console.log(3)
    }
script>

当点击 btn1 的时候,会依次输入 1,2,3,这就是事件冒泡,DOM0 级只支持冒泡阶段

DOM2

DOM2定义了两个方法:

  1. addEventListener 添加事件侦听器
  2. removeEventListener 删除事件侦听器

这两个方法均有三个参数:

  • 第一个参数是要处理的时间名称
  • 第二个参数是作为事件处理程序的函数名称
  • 第三个参数是一个布尔值,默认false表示使用冒泡机制,true表示捕获机制
<div id="btn">点击div>

<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",helloagain,false);
function hello(){
    console.log("hello");
}
function helloagain(){
    console.log("hello again");
}
script>

捕获冒泡的顺序

<div id="btn3">
        btn3
        <div id="btn2">
            btn2
            <div id="btn1">
                btn1
            div>
        div>
    div>
    <script>
        let btn1 = document.getElementById("btn1");
        let btn2 = document.getElementById("btn2");
        let btn3 = document.getElementById("btn3");
        btn1.addEventListener('click'function ({
            console.log('btn1捕获')
        }, true)
        btn1.addEventListener('click'function ({
            console.log('btn1冒泡')
        }, false)

        btn2.addEventListener('click'function ({
            console.log('btn2捕获')
        }, true)
        btn2.addEventListener('click'function ({
            console.log('btn2冒泡')
        }, false)

        btn3.addEventListener('click'function ({
            console.log('btn3捕获')
        }, true)
        btn3.addEventListener('click'function ({
            console.log('btn3冒泡')
        }, false)
    
script>

点击btn1,其结果为:btn3捕获 btn2捕获 btn1捕获 btn1冒泡 btn2冒泡 btn3冒泡

阻止冒泡

btn2.addEventListener(
  "click",
  function (ev{
    ev.stopPropagation();
    console.log("btn2捕获");
  },
  true
);


所有《每日一题》的 知识大纲索引脑图 整理在此:https://www.yuque.com/dfe_evernote/interview/everyday
你也可以点击文末的 “阅读原文” 快速跳转


用一个十年拉扯自己长大,
那时未来已达,星辰开花。


浏览 20
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报