最近在开发时遇到这样一个需求,一个表单列表报错后,滚动表单到能展示报错元素,做的时候发现clientWidth,offsetWidth,scrollWidth这几个概念自己有时候还是会弄混,所以想写篇文章记录一下。
clientHeight和clientWidth计算时包含元素的content,padding
不包括border,margin和滚动条占用的空间。对于inline的元素这个属性一直是0
offsetWidth/offsetHeight计算时包含 content + padding + border
不包括margin的元素的高度。对于inline的元素这个属性一直是0
代表元素距离父级元素的相对距离,但是父级元素需要具有relative定位,直到找到body,并且即使元素会被滚动,这个值也不会改变
scrollWidth/scrollHeight 返回值包含 content + padding + 溢出内容的尺寸,这个只针对dom的子元素出现溢出情况时,才有效果,不然它始终和clientHeight相等
代表在有滚动条时,滚动条向下滚动的距离也就是元素顶部被遮住部分的高度。在没有滚动条时scrollTop==0。
它返回一个对象,其中包含了left、right、top、bottom四个属性,分别对应了该元素的左上角和右下角相对于浏览器窗口(viewport)左上角的距离
注意
:当元素溢出浏览器的视口,值会变成负数。
但是滚动元素是从可视区域的左上角和右下角开始计算,如果想获取滚动元素整体的坐标,需要加上滚动距离
var X = node.getBoundingClientRect().left+node.scrollLeft;
var Y = node.getBoundingClientRect().top+node.scrollTop;
有一个列表,当我们输入文段编号,列表会将选中文段滚动到视图中
大概是这样
实现思路就是,去拿到选中元素的clientHeight和offsetTop,并和列表的高度区间做比较,计算出元素是在列表视口的内部,还是溢出的视口,如果溢出了视口,那么就回滚。
笔者用react写的,直接附上代码吧
dom
<div className='container'>
<div className='scroll' ref={(ref) => (this.scrollRef = ref)}>
{new Array(15).fill(0).map((_item, index) => (
<p
key={index}
ref={(ref) => (this.pRef[`ref${index}`] = ref)}
style={{ backgroundColor: Number(el) === index ? 'red' : '' }}
>{`这是第${index}文段`}</p>
))}
</div>
</div>
less
.container{
height: 340px;
width: 500px;
margin: auto;
margin-top: 100px;
border:1px black solid;
overflow: hidden;
padding: 10px;
position: relative;
display: flex;
align-items: center;
justify-content:space-between;
flex-direction: column;
}
.scroll{
height: 300px;
width: 500px;
overflow-y: scroll;
border:1px solid orange;
p{
text-align: center;
font-size:22px;
color:#9ef64d;
}
核心方法
const { value } = this.state;
// 滚动视口的高度
const containerHeight = this.scrollRef.clientHeight;
// 滚动视口距离浏览器顶部的距离
const containerOffsetTop = this.scrollRef.getBoundingClientRect().top;
// 选中元素距离浏览器的高度
const { top } = this.pRef[`ref${value}`].getBoundingClientRect();
// needScroll就是元素底部距离滚动容器顶部的距离,再减去20像素,保证出现在视口中间
const needScroll = top - containerOffsetTop - 20;
if (needScroll > containerHeight || needScroll < 0) {
// 将选中元素放入容器视口中
const timer = setTimeout(() => {
this.scrollRef.scrollTop = this.scrollRef.scrollTop + needScroll;
clearTimeout(timer);
}, 0);
}
本文整理了clientWidth,offsetWidth,scrollWidth的概念,以及它们所衍生出来的offsetTop,scrollTop的使用,并加上了一个不算复杂的demo,希望能对你有用,当然,如果可以,笔者也希望你能点个赞再走呢
https://www.ruanyifeng.com/blog/2009/09/find_element_s_position_using_javascript.html
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop