DOM事件进阶


事件流

事件流与两个阶段说明

概念

事件流:指的是事件完整执行过程中的流动路径

事件流

假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段

捕获阶段是 从父到子 冒泡阶段是从子到父

实际工作都是使用事件冒泡为主

事件捕获

概念

从DOM的根元素开始去执行对应的事件 (从外到里)

语法:事件源.addEventListener('事件方式',事件处理函数,是否使用捕获机制)

addEventListener第三个参数传入 true 代表是捕获阶段触发(很少使用)

若传入false代表冒泡阶段触发,默认就是false

若是用 L0 事件监听(on事件监听),则只有冒泡阶段,没有捕获

  

事件冒泡

概念

当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡

简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的 同名事件

L0事件监听,L2事件监听默认都是冒泡

  

阻止冒泡

阻止事件冒泡

因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素

若想把事件就限制在当前元素内,就需要阻止事件冒泡

阻止事件冒泡需要拿到事件对象

语法:事件对象.stopPropagation()

此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效

    p.addEventListener('click', function (e) {
      console.log('p')
      // 阻止事件冒泡
      e.stopPropagation()
    })

阻止默认行为

我们某些情况下需要阻止默认行为的发生,比如 阻止 链接的跳转,表单域跳转

语法:事件对象.preventDefault()

  链接
  

解绑事件

传统on注册(L0)

绑定事件:事件源.onxxxx = function () {}

解绑事件: 事件源.onxxxx = null

  • 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
  • 直接使用null覆盖偶就可以实现事件的解绑
  • 都是冒泡阶段执行的,无法开启捕获阶段
 
 

事件监听注册(L2)

绑定事件:事件源.addEventListener('事件类型', 处理函数)

解绑事件:事件源.removeEventListener('事件类型', 处理函数名)

  • 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)
  • 后面注册的事件不会覆盖前面注册的事件(同一个事件)
  • 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
  • 必须使用removeEventListener('事件类型', 事件处理函数名, 是否开启捕获阶段)
  • 匿名函数无法被解绑
 
 

事件委托

概念

事件委托:把事件委托给上级元素,利用事件流的特征解决一些开发需求的知识技巧

优点:

减少注册次数,可以提高程序性能,动态创建的元素也可以有事件了

原理:

事件委托其实是利用事件冒泡的特点。 给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件

实现:

事件对象.target:最先触发事件的元素 ,标签

事件对象.target. tagName :可以获得真正触发事件的元素 ,返回大写的标签名

  
  

事件委托步骤:

? 1.给上级元素注册事件
? 2.利用事件对象.target找到最先触发元素
? 3.用tagName查看是否是我们要找的元素

其他事件

页面加载事件

load

事件名:load

触发方式:加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件

使用场景:监听页面所有资源加载完毕: 给 window 添加 load 事件

 

  

注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件

 


DOMContentLoaded

事件名:DOMContentLoaded

触发方式:当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像等完全加载

使用场景: 监听页面DOM加载完毕: 给 document 添加 DOMContentLoaded 事件

 

  

滚动事件

绑定/添加滚动事件

事件名:scroll

触发方式:滚动条在滚动的时候持续触发的事件

使用场景: 谁有滚动条,给谁加滚动事件

  • 监听某个元素的内部滚动直接给某个元素加即可
  • 监听整个页面滚动: 给 window 或 document 添加 scroll 事件

 

获取位置

scrollLeft和scrollTop (属性)

使用场景:

  • 在scroll事件里面获取被卷去的距离
  • 获取被卷出的大小, 获取元素内容往左、往上滚出去看不到的距离

这两个值是可读写的,不仅可以获取,还可以设置

  

滚动到指定的坐标

语法:元素.scrollTo(x, y)

使用场景:把内容滚动到指定的坐标

btn.addEventListener('click', function () {
      // 返回顶部,设置上卷距离为0
      // document.documentElement.scrollTop = 0
      window.scrollTo(0,0)
    }) 

页面尺寸事件

绑定/添加滚动事件

事件名:resize

触发方式:窗口尺寸改变的时候触发事件

使用场景: 检测屏幕宽度: 给 window 添加 resize 事件

    window.addEventListener('resize', function () {
      const w = document.documentElement.clientWidth
      console.log(`当前页面宽度:${w}`)
    })

元素尺寸与位置

获取元素宽高

属性名:clientWidth和clientHeight

使用场景:获取元素的可见部分宽高:内容 + padding(不包含边框,margin,滚动条等)

clientWidth和clientHeight

属性名:offsetWidth和offsetHeight

使用场景:获取元素的自身宽高,包含元素自身设置的宽高、padding、border

元素尺寸

注意

  1. 获取出来的是数值,方便计算
  2. 获取的是可视宽高, 如果盒子是隐藏的,获取的结果是0
  3. 以上两种属性只能获取,不能设置
  4. 获取页面宽高,通常使用clientWidth和clientHeight,获取元素宽高,通常使用:offsetWidth和offsetHeight

获取位置

属性名:offsetLeft和offsetTop

使用场景:获取元素距离自己定位父级元素的左、上距离,参照定位元素的位置距离

方法名:getBoundingClientRect

语法:element.getBoundingClientRect()

返回值:元素的大小及其相对于视口的位置

注意:

  1. offsetLeft和offsetTop 注意是只读属性,只能获取,不能设置
  2. offsetLeft和offsetTop 以带有定位的父级为参考坐标,如果上级中都没有定位则以文档左上角 为准

元素尺寸与位置属性