JavaScript判断元素是否在可视区域的三种方法

 更新时间:2023年12月07日 09:58:27   作者:WebGirl  
这这篇文章给大家总结了JavaScript判断元素是否在可视区域的三种方法,getBoundingClientRect,IntersectionObserver和offsetTop、scrollTop这三种方法,文中通过代码示例给大家介绍的非常详细,需要的朋友可以参考下

方法1:getBoundingClientRect

用法

let domRect = dom.getBoundingClientRect();

DOMRect:{
  x/left:视图原点(左上角)距离dom左边框距离,
  y/top:视图原点(左上角)距离dom上边框距离,
    right:视图原点(左上角)距离dom右边框距离,
    bottom:视图原点(左上角)距离dom底边框距离,
    width:dom的宽度,标准盒模型,width = 宽度+padding+border;怪异盒模型,width = 设置的宽度,
    height:dom的高度,
}

所以我们可以根据DOMRect的中的各个属性来判断dom是否在可视区域内。

eg:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>getBoundingClientRect可视区域</title>
  <style>
    * {
      margin: 0
    }
    .circle-wrap {
      position: fixed;
      top: 50px;
      right: 50px;
      padding: 10px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      width: 140px;
      background: #fff;
    }

    .circle-wrap .circle {
      display: inline-block;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: red;
    }

    .card-wrap {
      height: 2000px;
      width: 3000px;
      margin-top: 100px;
    }

    .card-wrap .card {
      width: 200px;
      height: 200px;
      padding: 20px;
      box-sizing: border-box;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      margin-top: 500px;
      margin-left: 500px;
    }
  </style>
</head>

<body>
  <div class="circle-wrap">
    <span>当下方的卡片在可视区域内,我的圈圈是绿色,否则是红色</span>
    <span class="circle"></span>
  </div>
  <div class="card-wrap">
    <div class="card">我是一个卡片</div>
  </div>
  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js"></script>
  <script>
    const card = document.querySelector(".card");
    const circle = document.querySelector(".circle");
    const getBoundingClientRectJudge = () => {
      let domRect = card.getBoundingClientRect();
      console.log(domRect)
      let ch = document.documentElement.clientHeight;
      let cw = document.documentElement.clientWidth;
      let isInsert = true;
      if (domRect.bottom < 0 || domRect.top > ch || domRect.right < 0 || domRect.left > cw) {
        isInsert = false;
      }
      let background = null
      if (isInsert) {
        background = "green"
      } else {
        background = "red"
      }
      circle.style.background = background
    }
    window.addEventListener("scroll", _.throttle(getBoundingClientRectJudge, 500))
    getBoundingClientRectJudge()
  </script>
</body>

</html>

效果图:

问题

getBoundingClientRect并不能满足所有情况,甚至说,它只能满足一种情况的判断,那就是需要判断的那个dom节点,它只身处在一个滚动条的情况下。什么意思呢,就是它所有的祖先节点,加起来的滚动条只有1个,如果它父节点有滚动条,父父节点也有滚动条,那这种方法就不好用了,请看示例:

下面展示的结果是错误的,圈圈应该是红色才对。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>getBoundingClientRect可视区域</title>
  <style>
    * {
      margin: 0
    }

    body {
      height: 2000px;
      width: 3000px;
    }

    .circle-wrap {
      position: fixed;
      top: 50px;
      right: 50px;
      padding: 10px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      width: 140px;
      background: #fff;
    }

    .circle-wrap .circle {
      display: inline-block;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: red;
    }

    .card-wrap {
      height: 400px;
      width: 600px;
      margin-top: 100px;
      margin-left: 100px;
      border: 1px solid green;
      overflow: auto;
    }

    .card-wrap .card {
      width: 200px;
      height: 200px;
      padding: 20px;
      box-sizing: border-box;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      margin-top: 500px;
      margin-left: 500px;
    }

    .head {
      width: 100%;
      height: 100px;
      background: pink;
      /* position: fixed; */
      top: 0;
      left: 0;
    }
  </style>
</head>

<body>
  <!-- <div class="head"></div> -->
  <div class="circle-wrap">
    <span>当下方的卡片在可视区域内,我的圈圈是绿色,否则是红色</span>
    <span class="circle"></span>
  </div>
  <div class="card-wrap">
    <div class="card">我是一个卡片</div>
  </div>
  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js"></script>
  <script>
    const card = document.querySelector(".card");
    const circle = document.querySelector(".circle");
    const getBoundingClientRectJudge = () => {
      let domRect = card.getBoundingClientRect();
      let ch = document.documentElement.clientHeight;
      let cw = document.documentElement.clientWidth;
      let isInsert = true;
      if (domRect.bottom < 0 || domRect.top > ch || domRect.right < 0 || domRect.left > cw) {
        isInsert = false;
      }
      let background = null
      if (isInsert) {
        background = "green"
      } else {
        background = "red"
      }
      circle.style.background = background
    }
    window.addEventListener("scroll", _.throttle(getBoundingClientRectJudge, 500))
    getBoundingClientRectJudge()
  </script>
</body>

</html>

由此,我们引出第二种方法,IntersectionObserver。

方法2:IntersectionObserver

用法

eg:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>getBoundingClientRect可视区域</title>
  <style>
    * {
      margin: 0
    }

    body {
      height: 2000px;
      width: 3000px;
    }

    .circle-wrap {
      position: fixed;
      top: 50px;
      right: 50px;
      padding: 10px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      width: 140px;
      background: #fff;
    }

    .circle-wrap .circle {
      display: inline-block;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: red;
    }

    .card-wrap {
      height: 400px;
      width: 600px;
      margin-top: 100px;
      margin-left: 100px;
      border: 1px solid green;
      overflow: auto;
    }

    .card-wrap .card {
      width: 200px;
      height: 200px;
      padding: 20px;
      box-sizing: border-box;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      margin-top: 500px;
      margin-left: 500px;
    }
    .head{
      width: 100%;
      height: 100px;
      background: pink;
      /* position: fixed; */
      top:0;
      left: 0;
    }
  </style>
</head>

<body>
  <!-- <div class="head"></div> -->
  <div class="circle-wrap">
    <span>当下方的卡片在可视区域内,我的圈圈是绿色,否则是红色</span>
    <span class="circle"></span>
  </div>
  <div class="card-wrap">
    <div class="card">我是一个卡片</div>
  </div>
  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js"></script>
  <script>
    const card = document.querySelector(".card");
    const circle = document.querySelector(".circle");
    const observer = new IntersectionObserver((changes) => {
      // changes是数组
      changes.forEach(one => {
        console.log(one)
        let isIntersecting = one.isIntersecting
        let background = null
        if (isIntersecting) {
          background = "green"
        } else {
          background = "red"
        }
        circle.style.background = background
      })
    })
    observer.observe(card)
    // console.log(observer)
    /* 取消观察特定的元素:observer.unobserve(dom) */
    /* 对象停止监听目标 observer.disconnect() */
  </script>
</body>

</html>

补充说明

IntersectionObserver可以传root,进一步判断dom是相对于哪个节点,来判断是否在可视区域内,默认rootdocument

const observer = new IntersectionObserver((changes) => {
      console.log(changes)
      changes.forEach(one => {
        console.log(one)
        let isIntersecting = one.isIntersecting
        let background = null
        if (isIntersecting) {
          background = "green"
        } else {
          background = "red"
        }
        circle.style.background = background
      })
    },{root:document.querySelector(".card-wrap")})

方法3:offsetTop、scrollTop

说明

  • offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离,其他方向相同
  • offsetWidth:元素两端算上外边框的宽度,其他方向相同
  • scrollLeftscrollTop:既可以确定当前元素的滚动状态,也可以设置元素的滚动位置
  • scrollWidthscrollHeight:确定元素内容的实际大小
  • clientWidth:元素内容区宽度加上左右内边距宽度,即clientWidth = content + padding
  • clientHeight:元素内容区高度加上上下内边距高度,即clientHeight = content + padding

使用

公式:

0 <= el.offsetTop - document.documentElement.scrollTop <= viewPortHeight

写法:

function isInViePortOfOne(el){
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight||document.body.clientHeight
    const offsetTop = el.offsetTop;
    const scollTop = document.documentElement.scrollTop
    const top = offsetTop - scollTop;
    return top <= viewPortHeight && top >= 0
}

以上就是JavaScript判断元素是否在可视区域的三种方法的详细内容,更多关于JavaScript判断元素是否在可视区域的资料请关注脚本之家其它相关文章!

相关文章

  • 开发跨浏览器的JavaScript方法说明

    开发跨浏览器的JavaScript方法说明

    IE是当前浏览器的一个异类,不过解决方法倒也相当简单,使用Firefox和Safari 之 类的浏览时,可以使用元素的setArribute方法来设置元素的class属性
    2008-08-08
  • postcss-pxtorem实现页面自适应的原理解析

    postcss-pxtorem实现页面自适应的原理解析

    postcss-pxtorem是一个PostCSS插件,用于将CSS中的像素值转换为rem单位,以实现响应式布局和适配不同屏幕尺寸的需求,本文给大家介绍postcss-pxtorem实现页面自适应的原理解析,感兴趣的朋友一起看看吧
    2023-12-12
  • JavaScript中Object和Function的关系小结

    JavaScript中Object和Function的关系小结

    JavaScript 中 Object 和 Function 的关系是微妙的,他们互为对方的一个实例。
    2009-09-09
  • Javascript this 的一些学习总结

    Javascript this 的一些学习总结

    相信有C++、C#或Java等编程经验的各位,对于this关键字再熟悉不过了。由于Javascript是一种面向对象的编程语言,它和C++、C#或Java一样都包含this关键字,接下来我们将向大家介绍Javascript中的this关键字
    2012-08-08
  • javascript动态创建表格及添加数据实例详解

    javascript动态创建表格及添加数据实例详解

    这篇文章主要介绍了javascript动态创建表格及添加数据,以实例形式分析了javascript动态创建表格的常用方法,包括不兼容IE6与兼容IE6的实现方法,非常具有实用价值,需要的朋友可以参考下
    2015-05-05
  • css与javascript跨浏览器兼容性总结

    css与javascript跨浏览器兼容性总结

    这篇文章主要介绍了css与javascript跨浏览器兼容性,包括常见的css兼容性问题与javascript兼容性问题,以及IE与Firefox等常用浏览器的兼容性分析,需要的朋友可以参考下
    2014-09-09
  • js实现操作cookie的常见方法总结【创建、读取、删除】

    js实现操作cookie的常见方法总结【创建、读取、删除】

    这篇文章主要介绍了js实现操作cookie的常见方法,结合实例形式分析了js操作cookie创建、读取、删除相关实现技巧与注意事项,需要的朋友可以参考下
    2020-03-03
  • JavaScript初学者需要了解10个小技巧

    JavaScript初学者需要了解10个小技巧

    在之前的编程语言排行榜中,我们曾介绍过转正在即的JavaScript语言,正如文章中阐明的那样,JavaScript不仅是最具活力的脚本语言,还是是最有用的编程语言之一。
    2010-08-08
  • 学前端,css与javascript重难点浅析

    学前端,css与javascript重难点浅析

    JavaScript是一种属于网络的脚本语言,已经被广泛用于Web应用开发,CSS(Cascading Style Sheet)层叠样式表单,今天给大家分享css与javascript重难点,感兴趣的朋友一起看看吧
    2020-06-06
  • js如何引入wasm文件

    js如何引入wasm文件

    这篇文章主要介绍了js如何引入wasm文件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04

最新评论