懒加载IntersectionObserver 深入理解

IntersectionObserver

callback

var observer = new IntersectionObserver(callback,options);
callback 监听元素的可见性
options   配置参数

callback 一般会触发两次,一次是目标进入视口(可见),另一次是完全离开(不可见)

  let observer = new IntersectionObserver(changes => {
    changes.forEach(change => {
      // 完全可见时为1,完全不可见时小于等于0
      console.log(change.intersectionRatio);

      // 被观察的目标元素,是一个 DOM 节点对象
      // 当前可视区域正在变化的元素
      console.log(change.target);

    })
  })
  如果没设置Option 就只触发两次

每一个属性的含义

time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒

target:被观察的目标元素,是一个 DOM 节点对象

rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null

boundingClientRect:目标元素的矩形区域的信息

intersectionRect:目标元素与视口(或根元素)的交叉区域的信息

intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0

    time: 3893.92
  🔽rootBounds: ClientRect
      bottom: 920
      height: 1024
      left: 0
      right: 1024
      top: 0
      width: 920

option

threshold 属性

threshold 属性决定了什么时候触发回调函数

new IntersectionObserver(
  entries => {/* ... */}, 
  {
    threshold: [0, 0.25, 0.5, 0.75, 1]
  }
);

比如,[0, 0.25, 0.5, 0.75, 1]就表示当目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。

root属性 rootMargin属性

root属性指定目标的容器节点(根元素)

属性 说明
root 监听元素的祖先元素 Element 对象
rootMargin 一个在计算交叉值时添加至根的边界盒(bounding_box)中的一组偏移量,类型为字符串,可以有效的缩小或扩大根的判定范围从而满足计算需要。语法大致和 CSS 中的 margin 属性等同,默认值是"0px 0px 0px 0px"
top、right、bottomleft
单位: “px”,”%
threshold 规定了一个监听目标与边界盒交叉区域的比例值,可以是一个具体的数值或是一组 0.0 到 1.0 之间的数组。若指定值为 0.0,则意味着监听元素即使与根有 1 像素交叉,此元素也会被视为可见.
{
  root: Element,
  rootMargin: string,
  threshold: number | number[]
}

默认

{
  root: null,
  rootMargin: "0px 0px 0px 0px",
  threshold: [0]
}

使用

方法 说明
disconnect() 使 IntersectionObserver 对象停止监听工作。
observe() 使 IntersectionObserver 开始监听一个目标元素。
unobserve() 使 IntersectionObserver 停止监听特定目标元素。

IntersectionObserver使用的是异步的方式,可以不用担心性能问题

  1. 开始观察某个猎物:observer.observe(el)
  2. 取消观察某个猎物:observer.unobserve(el)
  3. 自爆,关掉这个观察器:observer.disconnect()

可见性demo

const target = document.getElementById('target')

const observer = new IntersectionObserver((entries) => {
  const [entry] = entries

  if (entry.isIntersecting) {
    console.log('元素曝光了')
  }
})

observer.observe(target)

懒加载

为了惰性加载图片,当然不能把 img 的 src 直接设置成图片地址,不然浏览器直接就显示了。而一般是放在data-src属性中,或增加lazy-load类。

<img data-src="https://example.com/me.png" width="100px" height="50px" />
    
找到所有需要惰性加载的图片
var images = document.querySelectorAll('img[data-src]');
var observer = new IntersectionObserver(onIntersection);
images.forEach(img => { observer.observe(img); });
 const target = document.getElementById('ccc')

  const observer = new IntersectionObserver((entries) => {
    const [entry] = entries

    if (entry.isIntersecting) {
      entry.target.src='xxxx';
      // 取消监控
       observer.unobserve(entry.target)
    }
  })

  observer.observe(target)

当猎物进入到镜头后,isIntersecting会是true,不在镜头内就是false。

解释

  • intersectionRatio 相交比例。刚开始相交是0%,相交一半是50%,完全进入则是100%
  • isIntersecting 是否正在相交。intersectionRatio != 0 即正在相交。(后来增加的属性)
  • target 被观察的元素。
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if(entry.isIntersecting) {
        console.log("元素相交");
      } else {
        console.log("元素不相交");
      }
    });
  });

root 的理解

<div style="height:400px;overflow-y:scroll">
  <div style="height:200vh;background-color: khaki;"></div>
  <div id="ccc" style="height:500px;background-color: #b1ff6d;"></div>
  <div style="height:200vh;background-color: khaki;"></div>
</div>

  const target = document.getElementById('ccc')

  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        console.log("元素相交");
      } else {
        console.log("元素不相交");
      }
    });
  }, {
    root: document.querySelector('#aaa'),
  });

  observer.observe(target)

rootMargin

<div style="height:200vh;background-color: #f00d0d;"></div>
<div style="height:400px;overflow-y:scroll;" class="aaa">
  <div id="ccc" style="height:500px;background-color: #b1ff6d;"></div>
  <div style="height:200vh;background-color: khaki;"></div>
</div>

 const target = document.getElementById('ccc')
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        console.log("元素相交");
      } else {
        console.log("元素不相交");
      }
    });
  }, {
    root: document.querySelector('#aaa'),
    rootMargin:'50%'     //根 400px  50% 是200px
    /* 距离下面200px的时候相交*/
    /* 距离下面200px的时候不相交*/
  });
  observer.observe(target)
posted @ 2020-10-08 18:36  猫神甜辣酱  阅读(808)  评论(0编辑  收藏  举报