DOM事件进阶

事件流

事件流与两个阶段说明

概念

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

事件流

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

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

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

事件捕获

概念

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

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

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

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

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

<div>
<p></p>
</div>
<script>
// 事件监听:事件源.addEventListener('事件方式',事件处理函数,是否使用捕获机制)
// 事件流:事件触发后的流程
// 捕获阶段 true
// 冒泡阶段 false 默认
const div = document.querySelector('div')
const p = document.querySelector('p')
div.addEventListener('click', function () {
console.log('div')
},true)
p.addEventListener('click', function () {
console.log('p')
},true)
</script>

事件冒泡

概念

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

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

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

<div>
<p></p>
</div>
<script>
const div = document.querySelector('div')
const p = document.querySelector('p')
div.addEventListener('click', function () {
console.log('div')
})
p.addEventListener('click', function () {
console.log('p')
})
</script>

阻止冒泡

阻止事件冒泡

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

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

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

语法:事件对象.stopPropagation()

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

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

阻止默认行为

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

语法:事件对象.preventDefault()

<a href="http://www.baidu.com">链接</a>
<form action="http://www.baidu.com">
<input type="submit" value="提交">
</form>
<script>
const a = document.querySelector('a')
const form = document.querySelector('form')
a.addEventListener('click', function (e) {
// 阻止a默认跳转行为
// 事件对象.preventDefault() 阻止默认
e.preventDefault()
})
form.addEventListener('click', function (e) {
// 阻止表单默认提交行为
e.preventDefault()
})
</script>

解绑事件

传统on注册(L0)

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

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

  • 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
  • 直接使用null覆盖偶就可以实现事件的解绑
  • 都是冒泡阶段执行的,无法开启捕获阶段
<button>点击</button>
<script>
// 绑定事件
btn.onclick = function () {
console.log('onclick1')
}
btn.onclick = function () {
console.log('onclick2')
}
// 解绑事件
btn.onclick = null
</script>

事件监听注册(L2)

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

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

  • 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)
  • 后面注册的事件不会覆盖前面注册的事件(同一个事件)
  • 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
  • 必须使用removeEventListener('事件类型', 事件处理函数名, 是否开启捕获阶段)
  • 匿名函数无法被解绑
<button>点击</button>
<script>
const f1 = function () {
console.log('addEventListener1')
}
const f2 = function () {
console.log('addEventListener2')
}
// 绑定事件
// 匿名函数,无法解绑
btn.addEventListener('click', function () {
console.log('addEventListener0')
})
btn.addEventListener('click', f1)
btn.addEventListener('click', f2)
// 解绑事件
// 事件源.removeEventListener('事件类型', 事件处理程序的名称)
btn.removeEventListener('click', f2)
</script>

事件委托

概念

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

优点:

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

原理:

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

实现:

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

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

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10
<a href="">链接</a>
</li>
</ul>
<script>
// 事件委托:把事件委托给上级元素
/*
步骤:
1.给上级元素注册事件
2.利用事件对象.target找到最先触发元素
3.用tagName查看是否是我们要找的元素
*/
const ul = document.querySelector('ul')
// 注册事件
ul.addEventListener('click', function (e) {
// e.target有可能不是我们要找的元素,只有我们要找的元素才可以
if (e.target.tagName === 'LI') {
e.target.style.background = 'pink'
}
})
</script>

事件委托步骤:

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

其他事件

页面加载事件

load

事件名:load

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

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

<script>
// 加载事件:load
// 当外部资源加载完成后触发的事件
// 只要涉及带有路径的,都涉及加载
// load:所有资源加载 绑定在window
window.addEventListener('load', function () {
console.log('页面所有资源加载完成后执行')
const img = document.querySelector('img')
console.log(img)
})
</script>
<img src="./images/b01.jpg" alt="">
</body>

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

<img src="./images/b01.jpg" alt="">
<script>
// 加载事件:load
// 当外部资源加载完成后触发的事件
// 只要涉及带有路径的,都涉及加载
const img = document.querySelector('img')
img.addEventListener('load', function () {
console.log('图片加载完成后执行')
})
</script>
</body>

DOMContentLoaded

事件名:DOMContentLoaded

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

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

<script>
// DOM加载:当初始的HTML文档加载 绑定在document
document.addEventListener('DOMContentLoaded', function () {
console.log('当初始的HTML文档被完全加载和解析完成之后执行')
const img = document.querySelector('img')
console.log(img)
})
</script>
<img src="./images/b01.jpg" alt="">
</body>

滚动事件

绑定/添加滚动事件

事件名:scroll

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

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

  • 监听某个元素的内部滚动直接给某个元素加即可
  • 监听整个页面滚动: 给 window 或 document 添加 scroll 事件
<style>
div {
width: 200px;
height: 600px;
background-color: #eee;
overflow-y: scroll;
}
body {
height: 2000px;
}
</style>
<script>
// scroll:滚动事件 谁有滚动条,给谁加滚动事件
const div = document.querySelector('div')
div.addEventListener('scroll', function () {
console.log(`向上滚动${div.scrollTop}px`)
})
// 如果整个页面有滚动条,加给widow
window.addEventListener('scroll', function () {
console.log('滚动ing...')
})
</script>

获取位置

scrollLeft和scrollTop (属性)

使用场景:

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

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

<script>
const div = document.querySelector('div')
div.addEventListener('scroll', function () {
console.log(`向上滚动${div.scrollTop}px`)
})
window.addEventListener('scroll', function () {
// 整个页面再往出卷,那么卷的是html的scrollTop
// 获取html
// const html= document.documentElement
const html = document.querySelector('html')
console.log(`向上滚动${html.scrollTop}px`)
})
// scrollTop不仅可以获取,还可以设置
const btn = document.querySelector('input')
btn.addEventListener('click', function () {
// 返回顶部,设置上卷距离为0
document.documentElement.scrollTop = 0
})
</script>

滚动到指定的坐标

语法:元素.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
<style>
div {
width: 200px;
height: 200px;
padding: 10px;
margin: 10px;
border: 10px solid #000;
}
</style>
<div></div>
<script>
const div = document.querySelector('div')
div.style.width
// 获取宽高
// 获取页面宽高使用clientWidth
// clientWidth:包含:内容宽 + padding
console.log(div.clientWidth,div.clientHeight)
// offsetWidth:包含:内容宽 + padding + border
// 获取元素宽高:offsetWidth
console.log(div.offsetWidth,div.offsetHeight)
</script>

获取位置

属性名:offsetLeft和offsetTop

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

方法名:getBoundingClientRect

语法:element.getBoundingClientRect()

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

注意:

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

元素尺寸与位置属性

posted @   丫丫learning  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示