【每日一题NO.54】说下你对时间流的理解

前端印记

共 3077字,需浏览 7分钟

 ·

2021-10-12 11:56

人生苦短,总需要一点仪式感。比如学前端~

目录:

  • 事件

  • 事件流

    • 事件冒泡、事件捕获

  • DOM 事件处理

    • DOM0

    • DOM2

事件

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

事件流

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

事件冒泡、事件捕获

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

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

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

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("小石头");
  }
script>

但是会存在问题:

<div id="btn">点击div>
<script>
  var btn = document.getElementById("btn");
  btn.onclick = function(){
    console.log("小石头");
  }
  btn.onclick = function(){
    console.log("石头姐");
  }
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.onclick = function(){
      console.log(1)
  }
  btn2.onclick = function(){
      console.log(2)
  }
  btn3.onclick = function(){
      console.log(3)
  }
script>

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

DOM2

DOM2定义了两个方法:

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

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

  • 第一个参数是要处理的事件名称
  • 第二个参数是作为事件处理程序的函数名称
  • 第三个参数是一个布尔值,默认为false。false表示使用冒泡机制,true表示使用捕获机制
<div id="btn">点击div>
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", helloFun, false);
btn.addEventListener("click", helloAgainFun, false);
function helloFun(){
    console.log("hello");
}
function helloAgainFun(){
    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冒泡

阻止冒泡 event.stopPropagation()

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

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


END
愿你历尽千帆,归来仍是少年。
浏览 18
点赞
评论
收藏
分享

手机扫一扫分享

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

手机扫一扫分享

分享
举报