前言
最近在开发时遇到这样一个需求,一个表单列表报错后,翻滚表单到能展现报错元素,做的时候发现clientWidth,offsetWidth,scrollWidth这几个概念自己有时候仍是会弄混,所以想写篇文章记录一下。
clientWidth/clientHeight
clientHeight和clientWidth核算时包括元素的content,padding
不包括border,margin和翻滚条占用的空间。关于inline的元素这个特点一直是0
offsetWidth/offsetHeight
offsetWidth/offsetHeight核算时包括 content + padding + border
不包括margin的元素的高度。关于inline的元素这个特点一直是0
offsetTop/offsetLeft/offsetRight/offsetBottom:
代表元素间隔父级元素的相对间隔,但是父级元素需求具有relative定位,直到找到body,并且即使元素会被翻滚,这个值也不会改动
scrollWidth/scrollHeight
scrollWidth/scrollHeight 回来值包括 content + padding + 溢出内容的尺寸,这个只针对dom的子元素出现溢出状况时,才有效果,不然它始终和clientHeight相等
scrollTop
代表在有翻滚条时,翻滚条向下翻滚的间隔也便是元素顶部被遮住部分的高度。在没有翻滚条时scrollTop==0。
getBoundingClientRect()
它回来一个对象,其中包括了left、right、top、bottom四个特点,别离对应了该元素的左上角和右下角相关于浏览器窗口(viewport)左上角的间隔
留意
:当元素溢出浏览器的视口,值会变成负数。
但是翻滚元素是从可视区域的左上角和右下角开始核算,假如想获取翻滚元素整体的坐标,需求加上翻滚间隔
var X = node.getBoundingClientRect().left+node.scrollLeft;
var Y = node.getBoundingClientRect().top+node.scrollTop;
一个demo加深形象
有一个列表,当我们输入文段编号,列表会将选中文段翻滚到视图中
大概是这样
实现思路便是,去拿到选中元素的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,希望能对你有用,当然,假如可以,笔者也希望你能点个赞再走呢
参阅链接
www.ruanyifeng.com/blog/2009/0…
developer.mozilla.org/en-US/docs/…