Skip to content

怎样获取一个元素的位置和大小

发布日期:2024-01-23

本文推荐使用 pc 阅读,通过实时计算页面元素 a 的位置,解释了多个浏览器高度概念。


Element.getBoundingClientRect() 获取一个元素的宽高和位置

Element.getBoundingClientRect() 方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置。这个对象一共有8个属性,描述了元素矩形的位置:left、top、right、bottom、x、y、width、height

往下滚动页面可以看到今天的主角 a 元素,点击右侧的按钮调用 getBoundingClientRect() 吧,在控制台可以看到响应的输出。→_→

Element.getClientRects()

和上面的 getBoundingClientRect 行为相似,返回不同,返回的是一个 list。行内元素会产生自动换行这类看似分割整体的歧义,所以,会把行内元素(inline)根据它换行划分成多个盒子边界矩形(返回多个DOMRect)。

getClientRects 和 getBoundingClientRect 对比

scrollY、scrollTop 计算滚动距离

window.scrollY 是 window 的一个属性,它是只读的,表示垂直方向滚动的距离,它的值是 0

window.pageYOffset 是 scrollY 的一个别名,它的值是 0

document.documentElement.scrollTop 是 html 元素的一个属性,它的值是 0,值得注意的是,我们可以改写这个值来实现滚动到指定位置

// 滚动到顶部
document.documentElement.scrollTop = 0

offset? client? 获取元素位置和大小

留意下面这个 div,本文将基于这个 div 进行多种计算。

我是 a 元素,我是一个div,我有 2px 的 border, 10px 的 margin 和 padding

我的 offsetTop 是0, 我的 offsetLeft 是0,

我的 offsetHeight 是0,我的 offsetWidth 是0

我的 clientTop 是0, 我的 clientLeft 是0,

我的 clientHeight 是0,我的 clientWidth 是0

从上面的值的差异可以看出如下结论(误差来自于小数点)

clientWidth = width + padding

clientHeight = height + padding

offsetWidth = width + padding + border+水平滚动条的宽度

offsetHeight = height + padding + border+垂直滚动条的宽度

clientTop 其实就是 border-top

offsetTop 表示元素距离它的 offsetParent 的距离,即是距离当前元素最近的经过定位(position不等于static) 的父级元素。在本页面中是 $(main .vp-doc) 元素,尝试移动滚动条,使得 window.scrollY === offsetTop,此时 a 元素顶端所处的位置,正好和 $(main .vp-doc) 元素距离页面顶部的距离一致。

window.innerHeight 浏览器可视高度

innerHeight 返回窗口的文档显示区的高度,如果有垂直滚动条,也包括滚动条高度,它的值是 0。

innerWidth 返回窗口的文档显示区的宽度,如果有水平滚动条,也包括滚动条高度,它的值是 0。

获取这两个值不会导致浏览器回流,点击 scrollY 介绍下面的按钮刷新值。

计算元素是否处于画面可视区域

假设元素的 offsetParent 是 html 元素,要使得元素处于画面可视区域,浏览器滚动距离需要大于元素的 offsetTop(此时元素从下方出现),且浏览器滚动距离小于元素的 offsetTop 加上屏幕显示高度和元素高度的总和(此时元素从上方消失)。

const a = $('#a') // 判断 a 是否在屏幕可视区域
const isVisible = window.scrollY > a.offsetTop - window.innerHeight &&  window.scrollY < a.offsetTop + a.offsetHeight

而对于当前页面的 a 元素,计算方法如下,由于本页面的顶栏会遮挡正文内容,因此计算的时候需要额外减去顶栏高度

// html
<button style="position: fixed; right: 0; top: 50%; z-index: 99;" @click="getVisible">点击计算,a元素是否在画面可视区域?{{ a.isVisible }}</button>

// js
const a = reactive({
  isVisible: false
})
let el = document.getElementById('a')
let offsetTop = el.offsetTop
const offsetHeight = el.offsetHeight
const headerHeight = document.querySelector('.VPNav').offsetHeight
while(el.offsetParent) {
  el = el.offsetParent
  offsetTop += el.offsetTop
}
a.isVisible = window.scrollY > offsetTop - window.innerHeight &&  window.scrollY < offsetTop + offsetHeight - headerHeight

点击右边的按钮验证 →_→

scrollTo 滚动到指定位置

这不仅是一个 window 上的方法,你还可以在 element 上调用它,调用之后会滚动到指定的位置。

// 调用方法1
window.scrollTo(x, y)

// 调用方法2
window.scrollTo({
  top: 100,
  left: 100,
  behavior: "smooth",
})

Power by vitepress