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判断元素是否在可视区域的资料请关注脚本之家其它相关文章!

相关文章

  • 修改layui的后台模板的左侧导航栏可以伸缩的方法

    修改layui的后台模板的左侧导航栏可以伸缩的方法

    今天小编就为大家分享一篇修改layui的后台模板的左侧导航栏可以伸缩的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • JS实现标签页切换效果

    JS实现标签页切换效果

    这篇文章主要为大家详细介绍了JS实现标签页切换效果的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • 深入理解JS中的Promise.race控制并发量

    深入理解JS中的Promise.race控制并发量

    这篇文章主要为大家介绍了JS中的Promise.race控制并发量的深入理解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • JavaScript实现文本框中默认显示背景图片在获得焦点后消失的方法

    JavaScript实现文本框中默认显示背景图片在获得焦点后消失的方法

    这篇文章主要介绍了JavaScript实现文本框中默认显示背景图片在获得焦点后消失的方法,涉及javascript针对页面元素样式及属性的相关操作技巧,需要的朋友可以参考下
    2015-07-07
  • JavaScript实现字符雨效果

    JavaScript实现字符雨效果

    这篇文章主要为大家详细介绍了JavaScript实现字符雨效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • 使用javascript做的一个随机点名程序

    使用javascript做的一个随机点名程序

    这篇文章主要介绍了使用javascript做的一个随机点名程序,经测试,效果相当不错,需要的朋友可以参考下
    2014-02-02
  • vant uploader实现上传图片拖拽功能(设为封面)

    vant uploader实现上传图片拖拽功能(设为封面)

    这篇文章主要介绍了vant uploader实现上传图片拖拽功能(设为封面),这个功能在日常生活中经常会用到,操作非常方便,今天通过实例代码介绍实现过程,需要的朋友可以参考下
    2021-10-10
  • JavaScript处理解析JSON数据过程详解

    JavaScript处理解析JSON数据过程详解

    JSON 是 JavaScript 原生格式,也就是说在 JavaScript 中处理 JSON 数据不需要任何特殊的 API 或工具包。接下来,本文给大家介绍JavaScript处理解析JSON数据过程详解,感兴趣的朋友快来了解了解吧
    2015-09-09
  • 微信小程序canvas实现刮刮乐效果

    微信小程序canvas实现刮刮乐效果

    这篇文章主要为大家详细介绍了微信小程序canvas实现刮刮乐效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • JS中${}什么意思有什么作用

    JS中${}什么意思有什么作用

    在JavaScript中,${}用于模板文字(template literals),为ES6中新增的字符串方法,其作用是配合反单引号实现字符串拼,代替以前传统复杂的引号双引号与+的拼接,简介明了,非常好用,本文给大家介绍JS中‘${}‘什么意思有什么作用,感兴趣的朋友一起看看吧
    2023-08-08

最新评论