提问一下js里srolltop。元素的offset top clientHeight 是从哪里算的?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了提问一下js里srolltop。元素的offset top clientHeight 是从哪里算的?相关的知识,希望对你有一定的参考价值。

参考技术A 您好,这里是javascript中制作滚动代码的常用属性
页可见区域宽: document.body.clientWidth;网页可见区域高: document.body.clientHeight;网页可见区域宽: document.body.offsetWidth (包括边线的宽);网页可见区域高: document.body.offsetHeight (包括边线的宽);网页正文全文宽: document.body.scrollWidth;网页正文全文高: document.body.scrollHeight;网页被卷去的高: document.body.scrollTop;网页被卷去的左: document.body.scrollLeft;网页正文部分上: window.screenTop;网页正文部分左: window.screenLeft;屏幕分辨率的高: window.screen.height;屏幕分辨率的宽: window.screen.width;屏幕可用工作区高度: window.screen.availHeight;
offsetLeft
假设 obj 为某个 html 控件。
obj.offsetTop 指 obj 距离上方或上层控件的位置,整型,单位像素。
obj.offsetLeft 指 obj 距离左方或上层控件的位置,整型,单位像素。
obj.offsetWidth 指 obj 控件自身的宽度,整型,单位像素。
obj.offsetHeight 指 obj 控件自身的高度,整型,单位像素。
我们对前面提到的“上方或上层”与“左方或上层”控件作个说明。
例如:
<div id="tool">
<input type="button" value="提交">
<input type="button" value="重置">
</div>
“提交”按钮的 offsetTop 指“提交”按钮距“tool”层上边框的距离,因为距其上边最近的是 “tool” 层的上边框。
“重置”按钮的 offsetTop 指“重置”按钮距“tool”层上边框的距离,因为距其上边最近的是 “tool” 层的上边框。
“提交”按钮的 offsetLeft 指“提交”按钮距“tool”层左边框的距离,因为距其左边最近的是 “tool” 层的左边框。
“重置”按钮的 offsetLeft 指“重置”按钮距“提交”按钮右边框的距离,因为距其左边最近的是“提交”按钮的右边框。
以上属性在 FireFox 中也有效。
另 外:我们这里所说的是指 HTML 控件的属性值,并不是 document.body,document.body 的值在不同浏览器中有不同解释(实际上大多数环境是由于对 document.body 解释不同造成的,并不是由于对 offset 解释不同造成的),点击这里查看不同点。
标题:offsetTop 与 style.top 的区别
预备知识:offsetTop、offsetLeft、offsetWidth、offsetHeight
我们知道 offsetTop 可以获得 HTML 元素距离上方或外层元素的位置,style.top 也是可以的。追问

document.body.clientHeight是窗口高度么,不改变浏览器大小这个值是不是不会变

参考技术B 是指浏览器窗口可视区域的顶部。

JQ的offset().top与JS的getBoundingClientRect区别详解,JS获取元素距离视窗顶部可变距离

 壹 ? 引

我在 JQ的offset().top与js的offsetTop区别详解 这篇博客中详细分析了JQ方法offset().top与JS属性offsetTop的区别,并得出了一条offset().top = offsetTop - scrollTop的结论,不过此结论只适用于监听元素滚动条,而window的滚动条并不满足。那么在滚动window滚动条时如何获取元素距离视窗顶部的距离呢,这就不得说说本文的主角getBoundingClientRect方法。

 贰 ? 关于getBoundingClientRect()

我们可以先拷贝下面的代码,动手起来跟着操作一遍,印象会深刻,需要引入JQ,这里提供一个静态资源地址,进去搜索JQ直接复制地址引入即可:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="css/demo.css">
</head>
<body>
    <div class="child"></div>
</body>
<script src="https://cdn.staticfile.org/jquery/3.4.1/jquery.js"></script>
<script src="js/app.js"></script>
</html>
* {
    padding: 0;
    margin: 0;
    list-style: none;
    outline: none;
}

.child {
    margin-top: 200px;
    margin-left: 200px;
    height: 200px;
    width: 200px;
    background: #bbded6;
    border: 5px solid #8ac6d1;
}
// JS getBoundingClientRect()
let child = document.querySelector(‘.child‘);
console.log(child.getBoundingClientRect());

//JQ offset()
// let son = $(‘.child‘);
// son.offset();

// JS offsetTop
// child.offsetTop;

这里我们在页面定义了一个宽高各200px且包含5px边框的盒子,由于没设置box-size = ’border-box‘属性,所以盒子总宽高为210px,这里我们直接打印出getBoundingClientRect方法结果,如下:

技术图片

可以看到getBoundingClientRect()返回了一个 DOMRect 对象,该对象包含了元素多个属性,其中最显眼的widthheight毫无悬念就是元素宽高,除此之外还包含top,bottom,right,leftx,y属性。

不难猜出,topleft为元素左上顶点距离视窗顶端与左侧距离,而rightbottom为右下顶点距离视窗左侧与顶端距离。而xleft一致,ytop一致。

技术图片

现在修改代码,将css中的margin-top修改为1000px,同时使用scroll事件打印getBoundingClientRecttop值与滚动条距离,其它不变,像这样:

window.onscroll = function () {
    //输出top值与滚动条距离
    console.log(child.getBoundingClientRect().top, document.documentElement.scrollTop);
};

当滚动条滚动,可以发现getBoundingClientRect().top值加上document.documentElement.scrollTop的值终等于1000,而这1000正是元素距离视窗顶部的距离。

技术图片

现在将JQ的代码与输出offsetTop的代码取消注释,并加入到scroll事件中,再次滚动滚动条像这样:

// JS getBoundingClientRect()
let child = document.querySelector(‘.child‘);
let son = $(‘.child‘);
window.onscroll = function () {
    //输出getBoundingClientRect的top值,JQ的offset().top与offsetTop
  console.log(child.getBoundingClientRect().top,son.offset().top,child.offsetTop);
};

技术图片

可以看到getBoundingClientRect().top是顺着滚动条下移慢慢变小的,毕竟元素距离视窗顶部越来越近了,而offset().topoffsetTop一直保持1000,为什么呢?

首先,我们知道offsetTop获取的是元素距离自己最近的offsetParent(position为非static且距离自己最近的祖先元素)的距离,且这个距离不随滚动条滚动变化,也就是说这个距离开始是多少就是多少,是个恒定值。

而JQ的offset().top获取的是元素距离文档顶端的距离。怎么去理解这个文档呢,我们把浏览器网页可读范围比喻成一幅画,这幅画包含了html,所以如果html内容越多(比如给html设置上margin),这幅画就会越长;而视窗呢可以比喻成一块玻璃,我们透过玻璃看这幅画,如果画的高度比玻璃还高那就有了滚动条,当滚动往下拉时,等同于玻璃位置不变,但是画会往上移。

知道这个概念后,我们再来想想上面例子为什么offset().top一直不变,当滚动条下拉,画往上移,而画中的元素是随着画一起运动的,很明显该元素相对画顶端的距离也一直没变,这下总知道为啥是1000了吧。

getBoundingClientRect获取的是元素距离视窗顶端的距离,当画上移,元素肯定距离视窗顶端越来越近,所以这个距离一定越来越小。

 叁 ? getBoundingClientRect与offset().top的区别

那么到这,我们知道了getBoundingClientRect参照是视窗顶端,而JQ的offset().top参照的是文档,两者参照对象不同。

当监听的是window的滚动条时,元素的getBoundingClientRect().top会原来越小,而offset().top一直不变。

当监听某个元素的滚动条时,元素的getBoundingClientRect().top会与offset().top保持一致,比如我让一个ul包含了多个li,滚动ul的滚动条时,获取第一个li的相关属性,有兴趣可以将下面的代码替换一下:

技术图片
HTML
<ul>
    <li style="background: orange;">1</li>
    <li style="background: black;">2</li>
    <li style="background: blueviolet;">3</li>
    <li style="background: pink;">4</li>
</ul>

CSS
* {
    padding: 0;
    margin: 0;
    list-style: none;
    outline: none;
    box-sizing: border-box;
}

ul {
    width: 200px;
    height: 100px;
    overflow-y: scroll;
    margin: 100px;

}

li {
    width: 100px;
    height: 300px;
    line-height: 300px;
    text-align: center;
}

JS
let parent = document.querySelector(‘ul‘);
let child = document.querySelectorAll(‘li‘)[0];
parent.onscroll = function () {
    //输出getBoundingClientRect的top值,JQ的offset().top与offsetTop
    console.log(child.getBoundingClientRect().top, $(child).offset().top, child.offsetTop);
};
View Code

技术图片

可以看到getBoundingClientRect().topoffset().top的值完全一致。

 肆 ? 获取元素距离距离视窗顶部的可变距离

楼层导航,懒加载,返回顶部按钮等等,只要涉及scroll事件,都无法避免的要去计算某个元素距离视窗顶部的距离,经过前文的分析,不管是监听window滚动条还是元素滚动条,其实都有两种可行方法。

如果是监听的是window的滚动条,那么可以使用:

window.onscroll = function () {
    可变距离 = document.querySelector(‘元素‘).getBoundingClientRect().top
};

其次可以获取元素的offsrtTop减去滚动条距离,前提是得保证元素的offsetParent为html元素或者body:

var offsetTop = document.querySelector(‘元素‘).offsetTop;
window.onscroll = function () {
    可变距离 = offsetTop - document.documentElement.scrollTop;
};

如果监听的是元素的滚动条,获取元素内子元素距离视窗的高度可以使用JQ的offset().top:

document.querySelector(‘父元素‘).onscroll = function () {
    子元素可变距离 = $(‘子元素元素‘).offset().top;
};

其次可以使用子元素的offsetTop减去父元素滚动条距离,当然你也得保证子元素的offsetParent为html或body:

var parent = document.querySelector(‘父元素‘);
var son = document.querySelector(‘子元素‘);
parent.onscroll = function () {
    子元素可变距离 = son.offsetTop - parent.scrollTop;
};

 伍 ? 总

那么结合文章开头的另一篇博客以及本文,我们详细介绍了JQ的offset().top与JS的offsetTop以及getBoundingClientRect的区别:

我们知道了offset().top参照对象是文档上边界,当监听window滚动条,它的效果与offsetTop类似,都是固定不变的值,毕竟在元素上移时,整体的文档也上移了。

我们知道offsetTop的参照对象是一个可变的offsetParent,而且得到的值永远不变。

我们还知道了好用的getBoundingClientRect方法,它的参照对象是视窗顶端,不管滚动条是window还是元素的,我们可以时时拿到可变尺寸。

当然我们还了解了特定情况下,使用offsetTop - scrollTop一样能拿到这个可变值。

那么到这里,本文结束。

以上是关于提问一下js里srolltop。元素的offset top clientHeight 是从哪里算的?的主要内容,如果未能解决你的问题,请参考以下文章

scrollTop, offsetTop, pageYOffset, scrollY 的区别

js或jquery怎样获取htm中div控件相对于页面的left和top值解决方

js的各个offset!offsetHeight,offsetTop

jQuery中offset()方法,获取的top=0,left=0。

html元素的 height,clientHeight和offsetHeight之间的区别

js的offset啥意思