js-元素相交检测

Intersection Observer API 提供了一种异步检测目标元素与根元素或 viewport 相交情况变化的方法。检测一个元素是否出现在视口中也是它的一个应用。

下面这些情况都需要用到相交检测:

  • 图片懒加载:当图片滚动到可见时才进行加载;

  • 内容无限滚动:也就是用户滚动到接近内容底部时直接加载更多;

  • 在用户看见某个区域时执行任务或播放动画。

完整 API 见:Intersection Observer API - Web API 接口参考 | MDN


IntersectionObserver

构造器
1
2
3
4
5
6
7
const options = {
root: null,
rootMargin: '0px',
threshold: 0
}

const io = new IntersectionObserver(callback, options);

options 对象有以下三个字段:

  • root:指定根元素,必须是目标元素的父级元素。如果未指定或者为null,则默认为浏览器视窗。

  • rootMargin:根元素外边距,用于 root 元素和 target 发生交集时计算交集的区域范围,默认值为四个边距全是 0。

  • threshold:规定当根元素与目标元素相交区域面积为多大时触发回调函数。其值可以是单一的 number 也可以是 number 数组。默认值为 0(只要有一个 target 像素出现在 root 元素中,回调函数将会被执行);值为 1.0 意味着当 target 完全出现在 root 元素中时回调函数才会被执行;值为 [0, 0.25, 0.5, 0.75, 1] 意味着 target 元素在 root 元素的可见程度每多 25% 就执行一次回调。

callback 回调函数结构:

1
new IntersectionObserver((res: IntersectionObserverEntry) => {})
方法
IntersectionObserver.observe(target)

开始监听一个目标元素。

IntersectionObserver.unobserve(target)

停止监听特定目标元素。

这里的 target 是 DOM 元素。


IntersectionObserverEntry

IntersectionObserverEntry 接口描述了目标元素与其根元素容器在某一特定过渡时刻的交叉状态。IntersectionObserverEntry 的实例作为参数被传递到一个 IntersectionObserver 的回调函数中。

属性
IntersectionObserverEntry.isIntersecting

返回一个布尔值。如果返回 true,那么目标元素与根元素正从非交叉状态变换到交叉状态。如果返回 false,那么可以由此判断,变换是从交叉状态到非交叉状态。

IntersectionObserverEntry.target

与根元素出现相交区域改变的元素。


应用-图片懒加载

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
27
28
29
30
31
32
33
34
<template>
<div v-for="(src, i) in srcList" :key="i">
<img :data-img="src" :data-key="i" :data-lazy-img-list="i" />
</div>
</template>

<script setup lang="ts">
import {onMounted, nextTick} from "vue";

const srcList = ["https://", "", "", ...];

onMounted(() => {
lazyImg("[data-lazy-img-list]", srcList);
});

function lazyImg (el: string, arr: string[]) {
const io = new IntersectionObserver(res => {
res.forEach((v: any) => {
if (v.isIntersecting) {
const { src, i } = v.target.dataset;
v.target.src = src;
v.target.onload = () => {
io.unobserve(v.target);
console.log(arr[i]);
};
}
});
});
nextTick(() => {
document.querySelectorAll(el).forEach((img) => io.observe(img));
});
};

</script>
data-* 属性用法
定义

data-* 属性是一类被称为自定义数据属性的属性,它能让我们在所有 html 元素上嵌入自定义属性。

命名规则

data-* 的 * 可以任意命名,但必须遵循以下命名规则:
1、不能以 xml 开头,无论是大写还是小写;
2、名称不能包含任何分号;
3、不能包含大写字母。

获取数据方式
1
2
3
4
5
document.getElementByClassName("test")[0].dataset 
// 返回所有 data-* 属性值的 json 对象

document.getElementByClassName("test")[0].getAttribute("data-name")
// 返回 data-name 属性的值

在 css 中可以通过下面方法访问:

1
2
3
.test[data-name="xxx"] {
color: red;
}