一、实现过程
在用户浏览网页时,滑动条滚动到底部时加载新数据是常见的业务,会给用户带来良好的体验。
而实现无限滚动加载的方式有很多,可以通过第三方web组件库的相关api来实现,也可以通过原生js监听滚动距离来实现。
这里介绍第二种原生的实现方式,普适性更好。
-
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
- window.pageYOffset 返回当前窗口相对于初始包含块的垂直偏移量,即滚动条从顶部向下滚动了多少像素。
- 若 window.pageYOffset 不可用(例如在一些较旧的浏览器中)时,则使用 document.documentElement.scrollTop。document.documentElement.scrollTop 表示<html> 元素的滚动偏移量,同样是页面垂直方向上的滚动距离。
-
const vHeight = window.innerHeight || document.documentElement.clientHeight;
- window.innerHeight 返回浏览器窗口的内部高度,即视口的高度,不包括浏览器的地址栏、工具栏等。
- document.documentElement.clientHeight 是 <html> 元素的客户区高度,通常情况下与视口高度相同。
-
const pageHeight = document.documentElement.scrollHeight;
- document.documentElement.scrollHeight 表示 <html> 元素的完整高度,即整个页面内容的高度,包括需要滚动才能看见的部分。
当 滚动距离+视口高度 >= 页面内容高度 时,即滚动到底了。
在实际代码中可以把页面内容高度适度减去一定的像素,留出加载数据的提前量,避免用户滚动到底部时等待加载数据。
在滚动到底部时还有一个问题,那就是触发事件太过频繁,显然这是不行的。
这时就需要节流或者防抖了。这里选择节流的方式,通过节流,可以限制滚动事件触发请求的频率,确保在用户滚动过程中较为平滑地加载新内容,避免过于频繁地发送请求对服务器造成不必要的压力,同时也提升了用户体验。
封装一个节流函数throttle,传入事件执行函数和时间间隔即可。
二、最终代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div style="height: 3000px;width: 100%;background: gray;"></div>
</body>
<script>
const throttle = (fun, delay) => {
let last = 0;
let timer = null;
return function throttled(...args) {
const now = Date.now();
if (now - last >= delay) {
clearTimeout(timer); // 清除之前可能存在的定时器
fun.apply(this, args);
last = now;
} else if (!timer) { // 如果在delay时间内再次触发,重新设置定时器
timer = setTimeout(() => {
fun.apply(this, args);
timer = null;
}, delay - (now - last));
}
};
};
const handleScroll = function () {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const vHeight = window.innerHeight || document.documentElement.clientHeight;
const pageHeight = document.documentElement.scrollHeight;
if (vHeight + scrollTop >= pageHeight - 500) {
//-500是为了在滚动到底部前提前获取数据,提高用户体验
console.log("到底了, 发请求获取数据");
}
};
window.addEventListener('scroll', throttle(handleScroll, 500));
</script>
</html>