JS- Scroll 滚动实战

35 阅读2分钟

前言

在前端开发中,处理“位置”与“滚动”是实现无限滚动、锚点定位、图片懒加载等功能的基石。本文将带你深度解析 getBoundingClientRect 的高级用法,并厘清 Scroll 家族属性的计算逻辑。

一、 精准定位:如何获取元素在页面中的“绝对坐标”?

getBoundingClientRect() 返回的是相对于视口Viewport的坐标。如果页面发生了滚动,这个值会实时变化。若要获取元素相对于整个页面Document的固定位置,我们需要手动换算。

1. 计算公式

元素绝对位置=视口位置+页面已滚动距离元素绝对位置 = 视口位置 + 页面已滚动距离

2. 代码实现

const element = document.getElementById('yourElementId');
const rect = element.getBoundingClientRect();

// 兼容性获取页面滚动位移
const scrollX = window.scrollX || window.pageXOffset || document.documentElement.scrollLeft;
const scrollY = window.scrollY || window.pageYOffset || document.documentElement.scrollTop;

// 计算元素相对于文档左上角的绝对位置
const elementTop = rect.top + scrollY;
const elementLeft = rect.left + scrollX;

console.log(`绝对位置:Left: ${elementLeft}px, Top: ${elementTop}px`);

二、 滚动尺寸:深入理解 Scroll 家族

当内容溢出(overflow: auto/scroll)时,Scroll 属性决定了我们如何观察和控制滚动区域。

1. 核心属性详解

属性含义关键细节
scrollHeight内容区域的总高度没有滚动条出现时,元素内容区域的总高度(如果子元素高度大于当前元素高度,则scrollHeight为子元素高度+元素上下padding)
scrollWidth内容区域的总宽度没有滚动条出现时,元素内容区域的总宽度(如果子元素宽度度大于当前元素宽度,则scrollHeight为子元素宽度+元素左右padding)
scrollTop垂直滚动偏移量内容区顶部被隐藏的像素数。可读写,设置它可滚动页面。
scrollLeft水平滚动偏移量内容区左侧被隐藏的像素数。可读写,设置它可滚动页面。

2. 容易忽视的细节

  • 只读性scrollHeightscrollWidth只读的;而 scrollTopscrollLeft可读写的。
  • 滚动监听:通过监听 scroll 事件,可以实时捕获 scrollTop 的变化,这是实现“回到顶部”按钮的关键。

三、 实战:代码演示与效果分析

以下代码演示了如何在一个受限的容器内监测滚动状态:

<!doctype html>
<head> </head>

<body>
  <div id="parent" style="width: 99px; height: 88px; border: 1px solid red; position: relative; overflow: auto">
    <div id="child" style="width: 9999px; height: 8888px; background: green"></div>
    <!-- <div id="child" style="width: 100px; height: 100px; position: absolute; left: 0; top: 0; background: green"></div> -->
  </div>
</body>

<style>
  #parent::-webkit-scrollbar {
    width: 4px; /* 垂直滚动条宽度 */
    height: 4px; /* 水平滚动条高度 */
  }
</style>

<script lang="javascript">
  const parent = document.getElementById('parent')
  const child = document.getElementById('child')
  console.log(parent.scrollHeight, parent.scrollWidth) 
  console.log(parent.scrollTop, parent.scrollLeft)
  parent.addEventListener('scroll', function () {
    console.log('垂直滚动位置:', parent.scrollTop)
    console.log('水平滚动位置:', parent.scrollLeft)
  })
</script>

四、 总结:属性对比表

为了方便记忆,我们可以将 OffsetClientScroll 三大家族放在一起对比:

家族包含范围主要用途
Offset内容 + Padding + Border获取元素占用的物理空间
Client内容 + Padding获取元素内部可视区域的大小
Scroll完整内容区域(含隐藏部分)处理滚动交互与进度计算