JQ的offset().top与js的offsetTop区别详解

1、前言css

最近在作一个图片懒加载的插件,就纵轴(Y轴)而言,我须要时时获取图片的上偏移量,好判断是否已进入视图区域,而我所理解的是offsetTop应该是跟offset().top同样的,而后陷入了由于不了解它们区别,而带来BUG的死坑。这里经过实验整理,作个清晰好懂的笔记,若是你也想弄清,建议复制个人代码跟着操做,印象会更为深入。html

2、offset().top与offsetTop什么意思?它们都是相对谁的上偏移量?面试

offset().top是JQ的方法,须要引入JQ才能使用,它获取的是你绑定元素上边框相对于文档顶端的偏移量,咱们能够把文档理解成一幅图,这幅图包含了html,html内容越多图越长,浏览网页时,就是透过透明的玻璃(s视窗)在看这幅画。布局

offsetTop是原生JS的方法,它获取的是你绑定元素上边框相对离本身最近且position属性为非static的祖先元素的偏移量(后面会具体解释)。spa

区别一:offset().top与offsetTop偏移量参照对象不一样,offset().top始终是html,而offsetTop参照的对象是可变的。插件

你们能够先拷贝下面代码:3d

html部分
<ul class="contain">
    <li><div></div></li>
   <li><div></div></li>
<li><div></div></li> <li><div></div></li> </ul> css部分 body{ position:relative; padding:0; margin:0; /* display: table; */ } .contain{ list-style: none; height: 1000px; width: 800px; overflow: auto; margin-top:200px;
background-color:#ebc38d; } .contain
>li{ margin-bottom: 10px; } .contain>li>div{ background-color: #e4393c; width: 300px; height: 400px; } js部分 var ul = document.querySelector(".contain"); var div = document.querySelectorAll("div")[0]; function demo() { var top1 = div.offsetTop;//第一个div的上偏移量 var top2 = $(div).offset().top;//第一个div的上偏移量 var top3 =ul.scrollTop;//ul本身的滚动条已滚动的距离,默认是0,往下滚动慢慢变大 console.log(top2, top1, top3); }

demo()
ul.addEventListener("scroll", demo);

html本身生成补全,记得引入JQ,这里提供一个静态资源库,直接复制JQ地址引入就能够了。code

在css中我为ul加了一个上边距为200px,先不解决上边距坍塌的问题,这会致使整个body区域距离页头有200px的空白区域,以方便区分body和html,以下图html范围和body范围:htm

这是html的范围对象

这是body的范围,很明显比html要矮出200px的空白区域,由于html没有设置上margin,能够说文档和html范围是相同的:

打开控制台,咱们能够看到输出了200,0,0;

第一个200:offset().top的值是第一个div上边界相对html的上偏移量,由于有200px的margin,因此是200;

第二个0:offsetTop的值第一个div上边界相对body的上偏移量,由于从div往上找,第一个position属性为非static的(relative,absolute,fixed其一)的祖先元素是body,因此相对body。

第三个0:scrollTop的值容器ul滚动条滚动的距离,由于默认没有滚动,因此是0;

咱们来作下改变,将body的position:relative属性移动到html上,其它不变,像这样:

咱们能够看到此时输出:200,200,0;

第一个200:offset().top的值仍是第一个div相对html的上偏移量,由于margin的问题。

第二个200:offsetTop的值验证了咱们以前的概念,offsetTop的参照对象是第一个position不为static的祖先元素,此时被咱们修改为了html;

第三个0:容器ul的滚动条距离。

咱们将body的display:table的注释去掉,将html的position属性去掉并还给body。其它不变,像这样,毕竟布局中上margin坍塌原本就不合理:

此时的body已经跟html范围相同,不存在200px空白区域,虽然offsetTop参照的是body,offset().top参照的是html,但从两个参照对象的上边界而言,能够理解为参照的是统一对象。

能够看到控制台仍是输出200,200,0。

相同点:当无滚动条且offsetTop与offset().top参照对象相同时,它们获取的值相同。

 区别二:offsetTop获取的偏移量不随滚动条滚动变化,但offset().top跟这滚动条变化

咱们尝试滚动ul的滚动条,观察输出值的变化

能够看到offset().top的值随着滚动条滚动越变越小,由于第一个div的上边界与html的上边界愈来愈近了。

offsetTop的值从一开始的200一直就没变化,不受滚动条影响。

而ul的scrollTop也随着咱们的滚动条往下拉,有了滚动距离,也在慢慢变大。很好理解不是吗?

3、猜想:offset().top = offsetTop - scrollTop

JQ能拿到变化的上偏移量,原生JS怎么拿这个变化的值呢?参照上面试验,scrollTop变大的同时,offset().top也在随之变小,只有 offsetTop恒定不变。

不用猜想了,你们将滚动输出打印的数字作个计算,很明显,第一个数字 = 第二个数字  - 第三个数字,就算offset().top为负数也同样遵照规则:

那咱们能够得出这样一个规律:

当一个元素的offset().top与offsetTop的参照对象相同时,offset().top的值等于offsetTop的值减去scrollTop的值。

咱们将body的display属性注释掉,像这样

很明显,由于margin坍塌的问题,body和html之间又多了200px的空白间隔区域,offset().top与offsetTop的参照对象这下就不一样了,咱们滚动滚动条能够看到规则就不适用了:

4、总结

offsetTop与offset().top相同点:

1.当无滚动条且offsetTop与offset().top参照对象相同时,它们获取的值相同。

offsetTop与offset().top不一样点:

1.offset().top与offsetTop偏移量参照对象不一样,offset().top始终是文档,而offsetTop参照的对象是可变的。

2.offsetTop获取的偏移量不随滚动条滚动变化,但offset().top随着滚动条变化(注意滚动监听的是一个有滚动条的元素,而不是window)

一个规律:

1.当一个元素的offset().top与offsetTop的参照对象相同时,offset().top = offsetTop - scrollTop

仍是建议你们能照着练一遍,要不了多少时间,印象也会更深入,也欢迎你们的补充和纠正,毕竟我也可能有理解错误的地方。

另外,本文中的例子是元素有滚动条的状况,若是监听的是window的滚动条,这个结论就不适用,不过咱们能够利用JS的getBoundingClientRect解决,想知道getBoundingClientRect与offset().top以及offsetTop有何区别吗?欢迎阅读博主另外一篇博客:

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

转载请标明出处,谢谢。好困...........