Dom事件进阶、Dom节点总结

事件流

事件捕获和事件冒泡

简言之,捕获阶段是【从父到子】的传导过程,冒泡阶段是【从子向父】的传导过程。实际工作都是使用事件冒泡为主

如果事件是在冒泡阶段执行的,我们称为冒泡模式,它会先执行子盒子事件再去执行父盒子事件,默认是冒泡模式。

如果事件是在捕获阶段执行的,我们称为捕获模式,它会先执行父盒子事件再去执行子盒子事件。

<body>
  <h3>事件流</h3>
  <p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p>
  <div class="outer">
    <div class="inner"></div>
  </div>
  <script>
    // 获取嵌套的3个节点
    const outer = document.querySelector('.outer')
    const inner = document.querySelector('.inner')

    // 外层的盒子
    outer.addEventListener('click', function () {
      console.log('outer...')
    }, true) // true 表示在捕获阶段执行事件
    
    // 中间的盒子
    outer.addEventListener('click', function () {
      console.log('inner...')
    }, true)
  </script>
</body>
  1. addEventListener 第3个参数决定了事件是在捕获阶段触发还是在冒泡阶段触发
  2. addEventListener 第3个参数为 true 表示捕获阶段触发,false 表示冒泡阶段触发,默认值为 false
  3. 事件流只会在父子元素具有相同事件类型时才会产生影响
  4. 绝大部分场景都采用默认的冒泡模式(其中一个原因是早期 IE 不支持捕获)
阻止冒泡

阻止冒泡是指阻断事件的流动,保证事件只在当前元素被执行,而不再去影响到其对应的祖先元素。

<body>
  <div class="outer">
    <div class="inner">
      <div class="child"></div>
    </div>
  </div>
  <script>
    // 获取嵌套的3个节点
    const outer = document.querySelector('.outer')
    const inner = document.querySelector('.inner')
    const child = document.querySelector('.child')

    // 外层的盒子
    outer.addEventListener('click', function () {
      console.log('outer...')
    })
    // 中间的盒子
    inner.addEventListener('click', function (ev) {
      console.log('inner...')
      // 阻止事件冒泡
      ev.stopPropagation()
    })
    // 内层的盒子
    child.addEventListener('click', function (ev) {
      console.log('child...')

      // 借助事件对象,阻止事件向上冒泡
      ev.stopPropagation()
    })
      
  </script>
</body>

e.stopPropagation()可以阻止事件冒泡,捕获阶段也有效,e为事件对象

mouseovermouseout 会有冒泡效果

mouseentermouseleave 没有冒泡效果 (推荐)

阻止默认行为

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

e.preventDefault()可以阻止默认行为,e为事件对象

解绑事件

on事件方式,直接使用null覆盖偶就可以实现事件的解绑

btn.onclick = function(){
    alert('点击了')
}
// 解绑事件
btn.onclick = null

addEventListener方式,必须使用:removeEventListener(事件类型, 事件处理函数, [获取捕获或者冒泡阶段])

function fn(){
    alert('点击了')
} 
// 绑定事件
btn.addEventListener('click',fn)
// 解绑事件
btn.removeEventListener('click',fn)

匿名函数无法被解绑

事件委托

事件委托是利用事件流的特征解决一些现实开发需求的知识技巧,主要的作用是提升程序效率。 大量的事件监听是比较耗费性能的,有些情况下只需找到对应的父节点进行操作即可

给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件

事件对象.target. tagName可以获得真正触发事件的元素

<script>
  // 假设页面中有 10000 个 button 元素
  const buttons = document.querySelectorAll('table button')
  
  // 假设上述的 10000 个 buttom 元素共同的祖先元素是 table
  const parents = document.querySelector('table')
  parents.addEventListener('click', function (ev) {
    // console.log(ev.target);
    // 只有 button 元素才会真正去执行逻辑
    if(ev.target.tagName === 'BUTTON') {
      // 执行的逻辑
    }
  })
</script>

其他事件

页面加载事件

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

事件名:load

监听页面所有资源加载完毕:

window.addEventListener('load', function() {
    // xxxxx
})
元素滚动事件

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

很多网页需要检测用户把页面滚动到某个区域后做一些处理, 比如固定导航栏,比如返回顶部

window.addEventListener('load', function() {
    // xxxxx
})
页面滚动事件-获取位置

scrollLeftscrollTop (属性)

  1. 获取被卷去的大小
  2. 获取元素内容往左、往上滚出去看不到的距离
  3. 这两个值是可读写
div.addEventListener('scroll',function(){
    console.log(this.scrollTop)
})

开发中,我们经常检测页面滚动的距离,比如页面滚动100像素,就可以显示一个元素,或者固定一个元素

document.documentElement HTML 文档返回对象为HTML元素

window.addEventListener('scroll',function(){
    const n = document.documentElement.scrollTop
    console.log(n)
})
  1. 被卷去的头部或者左侧用那个属性?是否可以读取和修改?

    scrollTop / scrollLeft, 可以读取,也可以修改(赋值)

  2. 检测页面滚动的头部距离(被卷去的头部)用那个属性?

    document.documentElement.scrollTop

页面滚动事件-滚动到指定的坐标

scrollTo() 方法可把内容滚动到指定的坐标,元素.scrollTo(x, y)

window.scrollTo(0,1000)
// 页面滚到y轴1000像素的位置
页面尺寸事件

会在窗口尺寸改变的时候触发事件:resize

获取宽高:

  1. 获取元素的可见部分宽高(不包含边框,margin,滚动条等
  2. clientWidthclientHeight
  3. 获取出来的是数值,方便计算

元素尺寸于位置

简单说,就是通过js的方式,得到元素在页面中的位置,获取元素的自身宽高、包含元素自身设置的宽高、padding、border

获取出来的是数值,方便计算,注意: 获取的是可视宽高, 如果盒子是隐藏的,获取的结果是0

offsetLeftoffsetTop 注意是只读属性

  1. offsetWidthoffsetHeight是得到元素什么的宽高?

    内容 + padding + border

  2. offsetTopoffsetLeft 得到位置以谁为准?

    带有定位的父级

    如果都没有则以 文档左上角 为准

element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置

属性作用说明
scrollLeftscrollTop被卷去的头部和左侧配合页面滚动来用,可读写
clientWidthclientHeight获得元素宽度和高度不包含border,margin,滚动条 用于js获取元素大小,只读属性
offsetWidthoffsetHeight获得元素宽度和高度包含border、padding,滚动条等,只读
offsetLeftoffsetTop获取元素距离自己定位父级元素的左、上距离获取元素位置的时候使用,只读属性

日期对象

掌握 Date 日期对象的使用,动态获取当前计算机的时间。

ECMAScript 中内置了获取系统时间的对象 Date,使用 Date 时与之前学习的内置对象 console 和 Math 不同,它需要借助 new 关键字才能使用。

// 1. 实例化
  // const date = new Date(); // 系统默认时间
  const date = new Date('2020-05-01') // 指定时间
  // date 变量即所谓的时间对象

  console.log(typeof date)
// 1. 实例化
 const date = new Date();
 // 2. 调用时间对象方法
 // 通过方法分别获取年、月、日,时、分、秒
 const year = date.getFullYear(); // 四位年份
 const month = date.getMonth(); // 0 ~ 11

getFullYear 获取四位年份

etMonth 获取月份,取值为 0 ~ 11

getDate 获取月份中的每一天,不同月份取值也不相同

getDay 获取星期,取值为 0 ~ 6

getHours 获取小时,取值为 0 ~ 23

getMinutes 获取分钟,取值为 0 ~ 59

getSeconds 获取秒,取值为 0 ~ 59

时间戳是指1970年01月01日00时00分00秒起至现在的总秒数或毫秒数,它是一种特殊的计量时间的方式。

ECMAScript 中时间戳是以毫秒计的。

将来的时间戳 - 现在的时间戳 = 剩余时间毫秒数,剩余时间毫秒数 转换为 剩余时间的 年月日时分秒 就是 倒计时时间,比如 将来时间戳 2000ms - 现在时间戳 1000ms = 1000ms,1000ms 转换为就是 0小时0分1秒

**三种方式获取时间戳 **

  // 1. 实例化
  const date = new Date()
  // 2. 获取时间戳
  console.log(date.getTime())
// 还有一种获取时间戳的方法
  console.log(+new Date())
  // 还有一种获取时间戳的方法
  console.log(Date.now())

Date.now()只能得到当前的时间戳, 而前面两种可以返回指定时间的时间戳

节点操作

回顾之前 DOM 的操作都是针对元素节点的属性或文本的,除此之外也有专门针对元素节点本身的操作,如插入、复制、删除、替换等。

DOM树里每一个内容都称之为节点,元素节点(所有的标签 比如 body、 div,html 是根节点),属性节点(所有的属性 比如 href),文本节点(所有的文本)。

查找节点

DOM 树中的任意节点都不是孤立存在的,它们要么是父子关系,要么是兄弟关系,不仅如此,我们可以依据节点之间的关系查找节点。

父节点查找:

  1. parentNode 属性
  2. 返回最近一级的父节点 找不到返回为null

子元素.parentNode

子节点查找

  1. childNodes,获得所有子节点、包括文本节点(空格、换行)、注释节点等
  2. children 属性 (重点),仅获得所有元素节点,返回的还是一个伪数组

父元素.children

兄弟关系查找:

  1. 下一个兄弟节点,nextElementSibling 属性
  2. 上一个兄弟节点,previousElementSibling 属性
插入节点

在已有的 DOM 节点中插入新的 DOM 节点时,需要关注两个关键因素:首先要得到新的 DOM 节点,其次在哪个位置插入这个节点

  • createElement 动态创建任意 DOM 节点

  • cloneNode 复制现有的 DOM 节点,传入参数 true 会复制所有子节点,若为false,则代表克隆时不包含后代节点

    ,默认为false

  • appendChild 在末尾(结束标签前)插入节点

  • insertBefore,父元素.insertBefore(要插入的元素,在那个元素前面)

<body>
  <h3>插入节点</h3>
  <p>在现有 dom 结构基础上插入新的元素节点</p>
  <hr>
  <!-- 普通盒子 -->
  <div class="box"></div>
  <!-- 点击按钮向 box 盒子插入节点 -->
  <button class="btn">插入节点</button>
  <script>
    // 点击按钮,在网页中插入节点
    const btn = document.querySelector('.btn')
    btn.addEventListener('click', function () {
      // 1. 获得一个 DOM 元素节点
      const p = document.createElement('p')
      p.innerText = '创建的新的p标签'
      p.className = 'info'
      
      // 复制原有的 DOM 节点
      const p2 = document.querySelector('p').cloneNode(true)
      p2.style.color = 'red'

      // 2. 插入盒子 box 盒子
      document.querySelector('.box').appendChild(p)
      document.querySelector('.box').appendChild(p2)
    })
  </script>
</body>
删除节点

在 JavaScript 原生DOM操作中,要删除元素必须通过父元素删除 父元素.removeChild(要删除的元素)

如不存在父子关系则删除不成功

删除节点和隐藏节点(display:none) 有区别的: 隐藏节点还是存在的,但是删除,则从html中删除节点

M端事件

移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android 和 IOS 都有。触屏事件 touch(也称触摸事件),Android 和 IOS 都有。touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作

触屏touch事件说明
touchstart手指触摸到一个DOM元素时触发
touchmove手指在一个DOM元素上滑动时触发
touchend手指在一个DOM元素上移开时触发

swiper

  • 插件: 就是别人写好的一些代码,我们只需要复制对应的代码,就可以直接实现对应的效果

  • 熟悉官网,了解这个插件可以完成什么需求 https://www.swiper.com.cn/

  • 看在线演示,找到符合自己需求的demo https://www.swiper.com.cn/demo/index.html

  • 查看基本使用流程 https://www.swiper.com.cn/usage/index.html

  • 查看APi文档,去配置自己的插件 https://www.swiper.com.cn/api/index.html

  • 注意: 多个swiper同时使用的时候, 类名需要注意区分

重绘和回流

  1. 浏览器是如何进行界面渲染的

    解析(Parser)HTML,生成DOM树(DOM Tree)

    同时解析(Parser) CSS,生成样式规则 (Style Rules)

    根据DOM树和样式规则,生成渲染树(Render Tree)

    进行布局 Layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置,大小)

    进行绘制 Painting(重绘): 根据计算和获取的信息进行整个页面的绘制

    Display: 展示在页面上

  2. 重绘和回流

    回流(重排)

    当 Render Tree 中部分或者全部元素的尺寸、结构、布局等发生改变时,浏览器就会重新渲染部分或全部文档的

    过程称为 回流。

    重绘

    由于节点(元素)的样式的改变并不影响它在文档流中的位置和文档布局时(比如:color、background-color、

    outline等), 称为重绘

    重绘不一定引起回流,而回流一定会引起重绘。

  • 会导致回流(重排)的操作:
  • 页面的首次刷新
  • 浏览器的窗口大小发生改变
  • 元素的大小或位置发生改变
  • 改变字体的大小
  • 内容的变化(如:input框的输入,图片的大小)
  • 激活css伪类 (如::hover)
  • 脚本操作DOM(添加或者删除可见的DOM元素)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值