javaScript使用IntersectionObserver API来判断dom元素是否在可视区域内

87 阅读2分钟

1. 前言

在项目中的很多需求中,经常会遇到一些关于一些元素是否在可视区域的判定,关于这个情况的判断有很多种办法,例如可以通过可视区域的尺寸与向上滚动的尺寸再加上当前监听的dom元素所在的位置,就可以计算得出这个dom元素是否在可视区域,但是有很严重的问题就是,使用起来太麻烦了

2. IntersectionObserver API介绍

关于IntersectionObserver API的更详细的介绍,可以去参见MDN,以下只是简单介绍一些这个API

IntersectionObserver可以使用observe方法来对指定的dom元素进行监听是否在可视区域中,如果监听的dom元素进入了可视区域,就会触发IntersectionObserver中的回调函数,回调函数中携带一个参数,这个参数是一个数组,数组中的每个元素,就是已经进入了可视区域的dom元素

3. 使用示例

<!--
* @Author:WangZhiYu
* @Date: 2023/07/11 20:46:00
 * @LastEditors: wangzhiyu
 * @LastEditTime: 2023-07-11 21:19:13
-->
<!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>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .container {
        width: 1100px;
        margin: 0 auto;
      }
      .item {
        height: 400px;
        background-color: blue;
        margin: 20px 0;
        color: #fff;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
    </div>
    <script>
      // 使用intersection observer API来监听那些元素进入/退出了视口
      const ob = new IntersectionObserver(
        entries => {
          // console.log(entries, 'entries');
          // 所有监听的dom,以数组的方式呈现,其中属性target表示当前监听的元素,isIntersecting表示是否与视口交叉
          console.log(entries.filter(item => item.isIntersecting));

          // 获取所有在视口中的元素
          let interSectingArr = entries.filter(item => item.isIntersecting);

          // 循环元素并且进行内容填充操作
          interSectingArr.forEach(item => {
            item.target.textContent = '进入了视口';

            // 取消监听
            ob.unobserve(item.target);
          });
        },
        // intersectionObcserver的配置
        {
          // 表示元素和哪个元素交叉时会触发,默认值为null,也就是浏览器窗口
          root: null,
          // 可以通过配置rootMargin来延伸交叉的距离值,默认是一个盒子到达浏览器窗口就算交叉,配置了rootMargin为10之后就是盒子距离浏览器窗口为10px的时候就算交叉了
          // rootMargin: '10px',
          // 表示交叉的阈值,取值为:0-1,如果设置为0.5就表示监听的元素进入一半的时候就开始监听
          threshold: 0.1,
        }
      );

      // 获取所有要监听视口的dom并循环使用observeAPI监听
      let list = document.querySelectorAll('.item');
      list.forEach(item => {
        // 使用observe监听dom元素是否进入视口
        ob.observe(item);
      });
    </script>
  </body>
</html>

4. 效果图

效果图