交叉观察器

先简要介绍一下使用背景吧,页面进行滚动时,信息不断呈现(如图片、多行数据等),如果页面一次性加载所有数据,会造成卡顿,所以出现了图片懒加载、无限滚动、组件延迟加载等概念。而实现这些功能的前提是判断信息是否出现在可视区域内,交叉观察器就是一种方式。

1. 基础概念

intersectionObserve是浏览器提供的原生构造函数,观察元素和可视区域是否发生交叉。

这里我们要明确一个概念,可视区域不一定指整个浏览器窗口,指的是你想要展示数据的DOM元素的区域。

2. 基本使用

因为是构造函数,所以得先初始化。

1
let IO = new IntersectionObserver(callback, options);

介绍一下这两个参数:

  • callback

    callback接收两个参数:

    • entries

      一个intersectionObserverEntry对象数组,存储观察元素的信息。原因是观察的对象可能有很多个。

    • observer

      返回被调用的IO实例,通常无需操作。

  • options

    对象形式,记录一些配置信息:

    • root:被观察元素,不配置默认是浏览器窗口

    • threshold:交叉比例

    • rootMargin

实例方法

  • IO.observe(element):开始观察element元素
  • IO.unobserve([element]):结束观察
  • IO.disconnect():关闭观察器

3. 图片懒加载

1
2
3
4
5
<div id="viewport">
<img src="./place.jpg" data-src="xxxx">
<img src="./place.jpg" data-src="xxxx">
<img src="./place.jpg" data-src="xxxx">
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
let viewport = document.getElementById("viewport"); // 可视区域
let imgList = document.querySelectorAll(".imgs"); // 被观察元素


let options = {
root: viewport
}
let IO = new IntersectionObserver(IOCallback, options);

// 循环所有 img 标签,使它被观察
imgList.forEach((item) => {
IO.observe(item)
})

// 回调函数
function IOCallback(entries, observer) {
// 循环所有观察元素
entries.forEach(item => {
// 如果出现在可视区内,则替换 src
if (item.isIntersecting) {
console.info("出现在可视区内")
item.target.src = item.target.dataset.src // 替换 src
IO.unobserve(item.target) // 停止观察当前元素 避免不可见时候再次调用 callback 函数
}
});
}