壹 ❀ 引

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

 贰 ❁ 关于getBoundingClientRect()

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

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <link rel="stylesheet" href="css/demo.css">
  9. </head>
  10. <body>
  11. <div class="child"></div>
  12. </body>
  13. <script src="https://cdn.staticfile.org/jquery/3.4.1/jquery.js"></script>
  14. <script src="js/app.js"></script>
  15. </html>
  1. * {
  2. padding:;
  3. margin:;
  4. list-style: none;
  5. outline: none;
  6. }
  7.  
  8. .child {
  9. margin-top: 200px;
  10. margin-left: 200px;
  11. height: 200px;
  12. width: 200px;
  13. background: #bbded6;
  14. border: 5px solid #8ac6d1;
  15. }
  1. // JS getBoundingClientRect()
  2. let child = document.querySelector('.child');
  3. console.log(child.getBoundingClientRect());
  4.  
  5. //JQ offset()
  6. // let son = $('.child');
  7. // son.offset();
  8.  
  9. // JS offsetTop
  10. // child.offsetTop;

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

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

不难猜出,top和left为元素左上顶点距离视窗顶端与左侧距离,而right与bottom为右下顶点距离视窗左侧与顶端距离。而x与left一致,y与top一致。

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

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

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

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

  1. // JS getBoundingClientRect()
  2. let child = document.querySelector('.child');
  3. let son = $('.child');
  4. window.onscroll = function () {
  5. //输出getBoundingClientRect的top值,JQ的offset().top与offsetTop
  6. console.log(child.getBoundingClientRect().top,son.offset().top,child.offsetTop);
  7. };

可以看到getBoundingClientRect().top是顺着滚动条下移慢慢变小的,毕竟元素距离视窗顶部越来越近了,而offset().top与offsetTop一直保持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的相关属性,有兴趣可以将下面的代码替换一下:

  1. HTML
  2. <ul>
  3. <li style="background: orange;">1</li>
  4. <li style="background: black;">2</li>
  5. <li style="background: blueviolet;">3</li>
  6. <li style="background: pink;">4</li>
  7. </ul>
  8.  
  9. CSS
  10. * {
  11. padding: 0;
  12. margin: 0;
  13. list-style: none;
  14. outline: none;
  15. box-sizing: border-box;
  16. }
  17.  
  18. ul {
  19. width: 200px;
  20. height: 100px;
  21. overflow-y: scroll;
  22. margin: 100px;
  23.  
  24. }
  25.  
  26. li {
  27. width: 100px;
  28. height: 300px;
  29. line-height: 300px;
  30. text-align: center;
  31. }
  32.  
  33. JS
  34. let parent = document.querySelector('ul');
  35. let child = document.querySelectorAll('li')[0];
  36. parent.onscroll = function () {
  37. //输出getBoundingClientRect的top值,JQ的offset().top与offsetTop
  38. console.log(child.getBoundingClientRect().top, $(child).offset().top, child.offsetTop);
  39. };

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

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

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

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

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

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

  1. var offsetTop = document.querySelector('元素').offsetTop;
  2. window.onscroll = function () {
  3. 可变距离 = offsetTop - document.documentElement.scrollTop;
  4. };

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

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

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

  1. var parent = document.querySelector('父元素');
  2. var son = document.querySelector('子元素');
  3. parent.onscroll = function () {
  4. 子元素可变距离 = son.offsetTop - parent.scrollTop;
  5. };

 伍 ☸ 总

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

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

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

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

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

那么到这里,本文结束。

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

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

    一.前言 最近在做一个图片懒加载的插件,就纵轴(Y轴)而言,我需要时时获取图片的上偏移量,好判断是否已进入视图区域,而我所理解的是offsetTop应该是跟offset().top一样的,然后陷入了因 ...

  2. js获取元素到屏幕左上角的距离

    开发过程中经常会遇到 获取元素到屏幕左上角的距离, 当我们使用jQuery开发时,我们可以使用 $.offset()来获取准确的距离. 如果我们的项目中并没有引入jQuer的话,跟希望通过原生方法实现 ...

  3. 详解js变量、作用域及内存

    详解js变量.作用域及内存 来源:伯乐在线 作者:trigkit4       原文出处: trigkit4    基本类型值有:undefined,NUll,Boolean,Number和Strin ...

  4. [转]javascript console 函数详解 js开发调试的利器

    javascript console 函数详解 js开发调试的利器   分步阅读 Console 是用于显示 JS和 DOM 对象信息的单独窗口.并且向 JS 中注入1个 console 对象,使用该 ...

  5. js调试工具Console命令详解

    这篇文章主要介绍了js调试工具Console命令详解,需要的朋友可以参考下   一.显示信息的命令 复制代码 代码如下: < !DOCTYPE html> < html> &l ...

  6. 详解js和jquery里的this关键字

    详解js和jquery里的this关键字 js中的this 我们要记住:this永远指向函数运行时所在的对象!而不是函数被创建时所在的对象.this对象是在运行时基于函数的执行环境绑定的,在全局环境中 ...

  7. 详解js的bind、call、apply

    详解js的bind.call.apply 说明 虽然bind.call.apply都是js很基础的一块知识,但是我从未认真总结过这三者的区别. 由于公司后端是用的微服务架构,又没有中间层对接,导致前端 ...

  8. 详解js面向对象编程

    转自:http://segmentfault.com/a/1190000000713346 基本概念 ECMA关于对象的定义是:”无序属性的集合,其属性可以包含基本值.对象或者函数.“对象的每个属性或 ...

  9. jquery的offset().top与javascript的offsetTop区别?

    offset().top是jquery的方法,需引入jquery,它获取你绑定元素上边框相对于html上边界的偏移量 offsetTop是原生js的方法,它获取你绑定元素上边框相对于离自己最近且pos ...

随机推荐

  1. Java_输入整数求阶乘

    import java.util.Scanner;public class Work4{ public static void main(String[] args){ // 创建Scanner对象 ...

  2. dockerfile-格式和使用

    一.dockerfile格式 Dockerfile是一个包含用于组合映像的命令文本文档,可以使用在命令行中调用任何命令,Docker通过读取dockerfile中的指令自动生成映像.docker bu ...

  3. 【玩转SpringBoot】让错误处理重新由web服务器接管

    其实web服务器是会处理错误的 在web.xml还是随处可见的年代时(确实有点老黄历了),下面的这些配置应该都不陌生. 根据错误代码处理错误,如下图01: 根据异常类型处理错误,如下图02: 不过我们 ...

  4. python:json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes问题解决

    有如下一个文件,内容如下 { "test1": "/root/test/test1.template", "test2": "/r ...

  5. js简单动画:匀速动画、缓动动画、多物体动画以及透明度动画

    主要实现以下几种简单的动画效果(其实原理基本相同): 1.匀速动画:物体的速度固定 2.缓动动画:物体速度逐渐变慢 3.多物体动画 4.透明度动画 效果实现: 1.匀速动画(以物体左右匀速运动为例) ...

  6. 开源Odoo13更新的模块功能信息(译文)

    本文来源江苏欧度软件:www.odooyun.com 本次Odoo13已于10月初发布,更新的模块有:Odoo会计模块.Odoo活动项目模块.Odoo13审批模块.Odoo评价.客户关系管理(CRM) ...

  7. Glide只播放一次Gif以及监听播放完成的实现方案

    需求: 近段时间正好有一个需求,是要实现Gif图只加载播放一次,并且要在Gif播放完毕后回调给系统的需求. 因为Glide 3系列的API与4系列还是有很大差距的,这里我们针对Glide 3.x和Gl ...

  8. SpringBoot系列——Jackson序列化

    前言 Spring Boot提供了与三个JSON映射库的集成: Gson Jackson JSON-B Jackson是首选的默认库. 官网介绍: https://docs.spring.io/spr ...

  9. SpringCloudConfig对称加密 yml配置文件while parsing a block mapping

    错误的配置!!! #-----------------db------------------ mybatis: type-aliases-package: com.book.product.pojo ...

  10. .NET 的未来:.NET 5

    前言 不知不觉中,.NET Framework 已经更新到 4.8,.NET Core 也更新到了 3.0 版本.那么 .NET 的未来怎么样呢? 计划 2019 年 Build 大会上,微软宣布下一 ...