这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
今天我们来学习如何在JavaScript中处理滚动事件,如何优化滚动事件的性能。
滚动事件简介
当我们滚动页面或者在某个元素上滚动时就会触发滚动事件,我们可以通过以下方式触发滚动事件
- 使用右侧滚动条
- 使用鼠标滚轮
- 点击锚点链接
- 调用JS函数
要监听滚动事件,使用addEventListener()
方法,事件名称为scroll
,代码如下:
targetElement.addEventListener('scroll', (event) => {
// 处理滚动事件
});
或者给目标元素的onscroll
属性绑定事件处理函数
targetElement.onscroll = (event) => {
// 处理滚动事件
};
监听整个网页滚动
要监听整个网页的滚动,我们给window
对象来绑定scroll
事件。
下面的例子展示了scroll
事件的绑定方式:
<div style="height: 6000px;">
很高很高很高的元素
</div>
<script>
window.addEventListener('scroll',(event) => {
console.log('滚动...');
});
</script>
当我们滚动页面时,可以发现scroll
事件处理函数一直在触发,控制台一直在打印 ''滚动...",直到我们停止滚动。
或者给window
对象的onscroll
属性绑定事件处理程序。
window.onscroll = function(event) {
console.log('滚动...');
};
注意:window 对象的 onscroll 属性与 document.body.onscroll 相同,可以将它们互换使用
document.body.onscroll = null;
console.log(window.onscroll); // null
滚动偏移量
window
对象有两个与滚动事件相关的属性:scrollX
和 scrollY
。
scrollX
和 scrollY
属性返回当前页面水平和垂直滚动的像素数。 scrollX
和 scrollY
是双精度浮点值,如果需要整数值,可以使用 Math.round()
将它们四舍五入。
如果文档根本没有滚动,则 scrollX
和 scrollY
为 0。
pageXOffset
和 pageYOffset
是 scrollX
和 scrollY
属性的别名。
请看下面的例子:
<div style="width: 3000px; height: 6000px;">
很高很高很高的元素
</div>
<script>
window.addEventListener('scroll',(event) => {
console.log(window.scrollX, window.scrollY)
});
</script>
监听元素滚动
和window
对象一样,我们可以给任何元素绑定scroll
事件,但要获取元素的滚动偏移量要使用scrollTop
和 scrollLeft
而不是 scrollX
和 scrollY
。
使用scrollTop
属性可以设置或获取元素内容垂直滚动的像素数, scrollLeft
属性获取或设置元素内容从其左边缘滚动的像素数。
下面例子我们将通过scrollLeft
和scrollTop
来去设置元素的滚动偏移量:
<!DOCTYPE html>
<html>
<head>
<title>JS scroll 滚动事件</title>
<style>
#scrollDemo {
height: 200px;
width: 200px;
overflow: auto;
background-color: #f0db4f
}
#scrollDemo p {
/* 展示滚动条 */
height: 300px;
width: 300px;
}
</style>
</head>
<body>
<div id="scrollDemo">
<p>JS scroll 事件示例</p>
</div>
<div id="control">
<button id="btnScrollLeft">Scroll Left</button>
<button id="btnScrollTop">Scroll Top</button>
</div>
<script>
let control = document.querySelector('#control');
control.addEventListener('click', function (e) {
// 获取滚动容器元素
let div = document.getElementById('scrollDemo');
// 获取点击的目标元素
let target = e.target;
// 处理每个按钮的行为
switch (target.id) {
case 'btnScrollLeft':
div.scrollLeft += 20;
break;
case 'btnScrollTop':
div.scrollTop += 20;
break;
}
});
</script>
</body>
</html>
优化处理滚动事件
当我滚动页面或者元素时会触发很多次滚动事件,如果在事件处理程序内需要处理很多逻辑,那么每次代码都会花费时间来执行,这将导致页面滚动产生卡顿。
事件节流
我们最好不要在滚动事件处理程序内处理复杂的逻辑操作,并且去设置间隔多长时间去执行一次处理处理程序。
错误示例:
window.onscroll = () => {
// 处理逻辑
};
正确做法:
<div style="height: 6000px;">
很高很高很高的元素
</div>
<script>
let scrolling = false;
window.onscroll = () => {
scrolling = true;
};
setInterval(() => {
if (scrolling) {
scrolling = false;
// 处理逻辑
console.log('滚动...')
}
},300);
</script>
你可能会奇怪,上面代码如何工作?
- 首先,定义了
scrolling
变量,表示当前页面是否在滚动,在滚动事件处理程序中修改其值为true
。 - 然后,如果滚动事件正在触发,则每 300 毫秒使用
setInterval()
执行滚动事件处理程序。
这种处理方式被称为节流,因为从每秒执行N次到每 300 毫秒执行1次事件处理程序,大大减少了事件处理程序的执行次数。
Passive Event
最近几年,现代浏览器支持了Passive Event
对于scroll
, touchstart
, wheel
等事件支持。它允许 UI 线程在将控制权交给自定义事件处理程序之前立即处理事件。
下面是Chrome 官方的视频介绍:点击查看视频。
在支持Passive Event
的 Web 浏览器中,需要将带有passive
属性的对象传入到任何不调用 preventDefault()
的事件侦听器中,如下所示:
document.addEventListener(
'scroll',
(event) => {
// 处理逻辑
},
{ passive: true }
);
如果没有Passive Event
,事件处理程序中的代码将始终在 UI 线程执行滚动之前被调用。
简单点来说,加了passive
属性,浏览器就知道了不用再去等待事件处理函数执行完毕再去进行滚动,而是页面先滚动完成,之后再去执行事件处理函数。这样就不会产生由于事件绑定的问题,造成页面滚动产生卡顿。
它的兼容性如何:点击查看Can IUse。
总结
- 当滚动网页或元素时会触发
scroll
事件 window
对象的scrollX
和scrollY
属性返回当前页面水平和垂直滚动的像素数。- 使用元素的
scrollTop
和scrollLeft
属性设置或获取元素垂直滚动和从其左边缘滚动的像素数。 - 使用事件节流来优化滚动事件性能。 在现代 Web 浏览器中,也可以使用
Passive Event
。
一起学习更多前端知识,微信搜索【小帅的编程笔记】,每天更新