概览
我们日常开发中,在面对懒加载、虚拟列表需求时,经常需要判断dom元素是否滚动到底、是否在可视区域。但是由于涉及的属性太多了,比如scrollTop、clientHeight、scrollHeight、getBoundingClientRect()等属性,现根据这两个场景,加深对相关的属性的认识。
一. 判断dom元素是否滚动到底
scrollTop: 元素顶部到元素可视区域顶部的像素距离(可读写)
clientHeight: 元素的像素高度,包括盒子内容content和内边距padding, 不包括边框外边距和水平滚动条(只读)
scrollHeight: 实际的内容区域,包括边框、内、外边距。
wrapper: 父元素盒子
content: 父元素包裹的内容区域
滚动前:
滚动中:
滚动到底:
滚动到底满足的条件:
const dom = document.querySelectorAll('.wrapper');dom[0].scrollTop + dom[0].clientHeight === dom[0].scrollHeight
总图:
举个例子
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div class="wrapper"><div class="content"><span>内容区域</span></div></div>
</body>
<script>// 父节点const dom = document.querySelectorAll('.wrapper')[0];// 子节点</script>
<style>.wrapper {width: 200px;height:300px;padding: 10px;border: 1px solid gray;overflow: auto}.content {height: 600px;background-color: pink;border: 1px solid gray;margin-top: 400px;}
</style>
</html>
web界面展示:
归纳总结:
- 有滚动条的前提是内容区域的高度/宽度大于外层盒子;
- 滚动前,scrollTop是0,滚动到底的过程就是滚动内容区域的过程,将隐藏在可视区域外的实际内容区域区域滚动完,就滚动到底了,实际内容区域 - 可视区域 === 滚动到底时滚动的距离(scrollTop)
- scrollHeight和clientHeight是固定值,在滚动过程中不会发生变化。
二. 判断dom元素是否在可视区域
getBoundingClientRect方法返回一个DOMRect对象,该对象包含了元素的位置和尺寸信息。DOMRect对象具有left、top、right、bottom、width、height等属性,可以用来计算元素在视口中的位置和大小。
检查dom元素是否在视口
const rect = element.getBoundingClientRect();const viewportWidth = window.innerWidth || document.documentElement.clientWidth;const viewportHeight = window.innerHeight || document.documentElement.clientHeight;const inViewport = rect.top < viewportHeight && rect.bottom > 0 &&rect.left < viewportWidth && rect.right > 0;
总结:
- getBoundingClientRect方法返回的top、left、bottom、right是相对于可视区域的视口中的位置,现以top和scrollTop来举例
比如:
top > 0
// 说明dom元素还没到视口的顶部0<top < clientHeight
// 说明dom元素还没到视口的顶部,但是已经在可视区域了top > clientHeight
// 说明dom元素还没到视口的顶部,且不在可视区域了top < 0// 说明dom元素已经超过视口的顶部了。
// 要判断是否在可视区域,需要结合bottom值
要判断dom元素完全暴露在可视区域,需要结合getBoundingClientRect方法返回的top、bottom、left、right四个属性和可视属性来对比确定。
拓展:
scrollIntoView: 将某个元素滚动到可视区域
比如代码
lastMessage.scrollIntoView({ behavior: 'smooth' })
lastMessage.scrollIntoView({ behavior: ‘smooth’ }); 这段代码用于将页面滚动到 lastMessage 这个元素上,并确保它可见在视口(viewport)中。
三. 总结
此篇文章主要是针对特定场景加深对scrollTop、clientHeight、scrollHeight、getBoundingClientRect()等属性的认识,实际场景以上的方案可能并非最佳,
比如
判断dom元素是否滚动到底,可以使用IntersectionObserver浏览器api.
其用法可参考往期文章:IntersectionObserver监听滚动事件
虚拟列表的最佳尝试可以使用requestAnimationFrame浏览器api,
其用法可参考往期文章:
requestAnimationFrame用法解析