Intersection Observer

创建

  1. 创建一个 IntersectionObserver 对象,并传入相应参数和回调用函数,该回调函数将会在目标(target)元素和根(root)元素的交集大小超过阈值(threshold)规定的大小时候被执行。
js 复制代码
const ob = new IntersectionObserver(callback, option)
  1. callback: 交叉改变后运行: 交叉/不交叉 => 不交叉/交叉
  2. option: 配置项目
  • root: 指定根(root)元素,用于检查目标的可见性。必须是目标元素的父级元素。如果未指定或者为null,则默认为浏览器视窗。
  • rootMargin: 根(root)元素的外边距。类似于 CSS 中的 margin 属性,比如 "10px 20px 30px 40px" (top, right, bottom, left)。如果有指定 root 参数,则 rootMargin 也可以使用百分比来取值。该属性值是用作 root 元素和 target 发生交集时候的计算交集的区域范围,使用该属性可以控制 root 元素每一边的收缩或者扩张。默认值为 0。
  • threshold: 阈值!可以是单一的 number 也可以是 number 数组,target 元素和 root 元素相交程度达到该值的时候 IntersectionObserver 注册的回调函数将会被执行。如果你只是想要探测当 target 元素的在 root 元素中的可见性超过 50%的时候,你可以指定该属性值为 0.5。如果你想要 target 元素在 root 元素的可见程度每多 25%就执行一次回调,那么你可以指定一个数组[0, 0.25, 0.5, 0.75, 1]。默认值是 0(意味着只要有一个 target 像素出现在 root 元素中,回调函数将会被执行)。该值为 1.0 含义是当 target 完全出现在 root 元素中时候 回调才会被执行。
  1. IntersectionObserver Entry

IntersectionObserverEntry 对象提供了目标元素与跟元素相交的详细信息。他有如下几个属性。

typescript 复制代码
interface IntersectionObserverEntry {
  readonly attribute DOMHighResTimeStamp time;
  readonly attribute DOMRectReadOnly? rootBounds;
  readonly attribute DOMRectReadOnly boundingClientRect;
  readonly attribute DOMRectReadOnly intersectionRect;
  readonly attribute boolean isIntersecting;
  readonly attribute double intersectionRatio;
  readonly attribute Element target;
};
  • time:发生相交到相应的时间,毫秒。
  • rootBounds:根元素矩形区域的信息,如果没有设置根元素则返回 null,图中蓝色部分区域。
  • boundingClientRect:目标元素的矩形区域的信息,图中黑色边框的区域。
  • intersectionRect:目标元素与视口(或根元素)的交叉区域的信息,图中蓝色方块和粉红色方块相交的区域。
  • isIntersecting:目标元素与根元素是否相交(满足预设的阈值条件)
  • intersectionRatio:目标元素与视口(或根元素)的相交比例。
  • target:目标元素,图中黑色边框的部分。
js 复制代码
var observer = new IntersectionObserver((entries) => {
  for (const entry of entries) {
    console.log(entry.time) // 发生变化的时间
    console.log(entry.rootBounds) // 根元素的矩形区域的信息
    console.log(entry.boundingClientRect) // 目标元素的矩形区域的信息
    console.log(entry.isIntersection) // 目标元素与视口(或根元素)是否相交(满足预设的阈值条件)
    console.log(entry.intersectionRect) // 目标元素与视口(或根元素)的交叉区域的信息
    console.log(entry.intersectionRatio) // 目标元素与视口(或根元素)的相交比例
    console.log(entry.target) // 被观察的目标元素
  }
}, {})

// 开始观察某个目标元素
observer.observe(target)

// 停止观察某个目标元素
observer.unobserve(target)

// 关闭监视器
observer.disconnect()

// 获取所有 IntersectionObserver 观察的 targets
observer.takeRecords()

请留意,你注册的回调函数将会在主线程中被执行。所以该函数执行速度要尽可能的快。如果有一些耗时的操作需要执行,建议使用 Window.requestIdleCallback() 方法。

所有区域均被 Intersection Observer API 当做一个矩形看待。如果元素是不规则的图形也将会被看成一个包含元素所有区域的最小矩形,相似的,如果元素发生的交集部分不是一个矩形,那么也会被看作是一个包含他所有交集区域的最小矩形。

这个有助于理解 IntersectionObserverEntry 的属性,IntersectionObserverEntry 用于描述 targetroot 的交集。

应用

图片懒加载

html 复制代码
<!-- html -->
<img src='default.png' data-src="xxxxx" />
<img src='default.png' data-src="xxxxx" />
<img src='default.png' data-src="xxxxx" />
<img src='default.png' data-src="xxxxx" />
js 复制代码
// js
const ob = new IntersectionObserver(
  entries => {
    for (const entry of entries) {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        ob.unobserve(img);
      }
    }
  },
  {
    root: null,
    rootMargin: 0,
    threshold: 0
  }
);

const imgs = document.querySelectorAll('img[data-src]')
imgs.forEach(img => {
  ob.observe(img)
})

下拉加载更多

方式:在dom元素之下存在一个加载动画。当加载动画出现在视口中,继续添加dom元素

html 复制代码
  <div>
    // 省略其他dom元素...
  </div>
  <loading></loading>
js 复制代码
const ob = new IntersectionObserver(
  entries => {
    if (entries[0].isIntersecting) {
      // ...添加doms
    }
  },
  {
    root: null,
    rootMargin: '0',
    threshold: 0
  }
);
const loading = document.querySelector('.loading');
ob.observe(loading);
相关推荐
gnip8 小时前
链式调用和延迟执行
前端·javascript
SoaringHeart8 小时前
Flutter组件封装:页面点击事件拦截
前端·flutter
杨天天.8 小时前
小程序原生实现音频播放器,下一首上一首切换,拖动进度条等功能
前端·javascript·小程序·音视频
Dragon Wu9 小时前
React state在setInterval里未获取最新值的问题
前端·javascript·react.js·前端框架
Jinuss9 小时前
Vue3源码reactivity响应式篇之watch实现
前端·vue3
YU大宗师9 小时前
React面试题
前端·javascript·react.js
木兮xg9 小时前
react基础篇
前端·react.js·前端框架
ssshooter9 小时前
你知道怎么用 pnpm 临时给某个库打补丁吗?
前端·面试·npm
IT利刃出鞘10 小时前
HTML--最简的二级菜单页面
前端·html
yume_sibai10 小时前
HTML HTML基础(4)
前端·html