Intersection Observer API

先说三个情景,第一是懒加载图片,会先加载你可视化区域内的图片,当滚动条往下滑动的时候才会加载下面的;第二是瀑布流布局,随着滚动条往下滑动,会一直加载图片出来是一个无限滚动的效果;第三个是播放一个视频,当滚动条往下滑动的时候,视频显示不全,此时视频是暂停,等往上滑动,视频出现完整的时候才会继续播放。这三个效果它们都跟滚动条有关系,按照常理我们要去检测滚动事件,计算滚动条的位置,然后做相应的处理,但是这样不仅效率低,而且滚动事件会不停的触发,并且实现起来比较麻烦。但是Intersection Observer API可以很好的帮我们处理这个问题。

Intersection表示交叉,指两个元素有个交叉,Observer 表示观察,简单来说就是观察两个元素有没有交叉。这个跟我们要实现的效果有啥关系呢?我们可以去试一下:

1.懒加载图片

先搭建一下场景:放一千张图片,其中src下的是静态资源,是默认图片,默认图片可以加入缓存所以加载起来很快,真实图片放到自定义属性data-src,目前显示的是默认图片,当图片进入到可视化区域的时候加载真实图片。

html 复制代码
<template>
    <div class="intersection-observer-api">
        <div class="header">
            这里是IntersectionObserverAPI组件的内容。
        </div>
        <div class="container card-border">
            <div class="item" v-for="item in 1000" :key="item">
                <img src="./imgs/1.jpg" alt="" data-src="https://picsum.photos/400/600?r=1" />
            </div>
        </div>

    </div>
</template>

整体思路是,我们去观察这个图片,如果这个图片跟我们的可视化区域有没有交叉,有交叉说明这个图片出现在我们的可视化区域里面,这个时候我们就把这个真实图片显示出来。

首先我们创建一个ob,就是观察者IntersectionObserver,这里面要传递一个回调函数,这个回调函数就是交叉的时候会运行,比如从交叉变到不交叉,或者从不交叉变到交叉,这个时候就会运行。与此同时,在调用这个回调函数的时候,还要传递一个配置,这个配置也很简单,一个是root,一个是rootMargin,一个是threshold

  • root: 表示要观察的元素跟谁交叉,比如我们观察那个图片要跟谁交叉,一般就是它的父元素或者父元素的父元素等等(不能是子元素),如果是null表示跟可视化区域交叉。

  • rootMargin:对交叉范围进行扩张,比如下面这个图就属于图片和可视化区域进行了交叉。

rootMargin可以把这个范围扩大,比如值为10px,就会把交叉范围往外扩大10px,如下图就算进行了交叉。当然可以收缩,值写为负值就行。

  • threshold :表示交叉的阈值,填写的范围在0~1之间,比如说0.5,就是说这个图片必须要有一半和可视化区域交叉才会触发回调函数。写0的话只要是碰上了就会执行。
js 复制代码
const ob = new IntersectionObserver(() => {
    console.log('进入视口');
}, {
    root: null, // 默认值为null,表示以浏览器视口作为容器
    rootMargin: '0px',  // 默认值为'0px'
    threshold: 0.1 // 默认值为0,表示当目标元素有10%的区域进入视口时触发回调
});

这样的话还差一个东西,就是要观察的目标,我们这里要观察的目标就是所有带有自定义属性data-src的图片。我们要先获取所有要观察的目标,然后去观察每个目标,怎么观察呢,就是给每个目标调用前面定义的ob对象的observe方法。

js 复制代码
// 获取所有要观察的图片元素
const imgs = document.querySelectorAll('img[data-src]');
// 观察每个图片元素  怎么观察就是调用ob对象的observe方法
imgs.forEach((img) => {
    ob.observe(img);
});

我们运行一下试试看。

可以看到后台已经有打印了,说明ob的回调方法已经调用了,但是为什么只调用了一次呢,明明有很多图片都交叉了,其实是这样的,它把所有的交叉结果会通过回调函数的参数entries传给你,entries是一个数组,我们去打印一下这个数组。

js 复制代码
const ob = new IntersectionObserver((entries) => {
    console.log(entries);
}, {
    root: null, // 默认值为null,表示以浏览器视口作为容器
    rootMargin: '0px',  // 默认值为'0px'
    threshold: 0.1 // 默认值为0,表示当目标元素有10%的区域进入视口时触发回调
});

可以看到这个数组有1000项,这是因为我们有一千个目标。但是我们交叉的图片只有20个,我们去看一下数组前20个元素,每一个元素都是一个Entry对象,每一个Entry对象里面就记录了这个目标跟我们的可视化区域是怎么交叉的,要注意两个属性,一个是target,表示目前观察的目标,第二个属性是isIntersecting,它表示目标是否和可视化区域进行了交叉。

可以看到前20个目标的isIntersectingtrue,表示目标和可视化区域已经交叉了。

所以我们就在回调函数里面去循环这个entries参数,判断每一项的isIntersecting,就可以知道这个目标跟我们的可视化区域到底有没有交叉。如果目标交叉了我们就可以直接通过Entry对象的target属性获取到目标,然后给目标的src属性重新赋值为data-src的值。然后调用ob对象的unobserve方法停止观察该目标。

js 复制代码
const ob = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
        if (entry.isIntersecting) { // 判断元素是否进入视口
            const img = entry.target; // 获取目标元素
            const dataSrc = img.getAttribute('data-src'); // 获取图片的真实路径
            if (dataSrc) {
                img.src = dataSrc; // 设置图片的src属性,开始加载图片
                img.removeAttribute('data-src'); // 移除data-src属性,避免重复加载
            }
            ob.unobserve(img); // 停止观察该元素,提高效率
        }
    });
}, {
    root: null, // 默认值为null,表示以浏览器视口作为容器
    rootMargin: '0px',  // 默认值为'0px'
    threshold: 0.1 // 默认值为0,表示当目标元素有10%的区域进入视口时触发回调

// 获取所有要观察的图片元素
const imgs = document.querySelectorAll('img[data-src]');
// 观察每个图片元素  怎么观察就是调用ob对象的observe方法
imgs.forEach((img) => {
    ob.observe(img);
});

效果如下,因为不是很明显,所以我给threshold值设置为0.5了,这样能看的清楚点。

待更新

相关推荐
RaidenLiu7 分钟前
告别陷阱:精通Flutter Signals的生命周期、高级API与调试之道
前端·flutter·前端框架
非凡ghost7 分钟前
HWiNFO(专业系统信息检测工具)
前端·javascript·后端
非凡ghost9 分钟前
FireAlpaca(免费数字绘图软件)
前端·javascript·后端
非凡ghost16 分钟前
Sucrose Wallpaper Engine(动态壁纸管理工具)
前端·javascript·后端
拉不动的猪17 分钟前
为什么不建议项目里用延时器作为规定时间内的业务操作
前端·javascript·vue.js
该用户已不存在24 分钟前
Gemini CLI 扩展,把Nano Banana 搬到终端
前端·后端·ai编程
地方地方26 分钟前
前端踩坑记:解决图片与 Div 换行间隙的隐藏元凶
前端·javascript
小猫由里香32 分钟前
小程序打开文件(文件流、地址链接)封装
前端
Tzarevich35 分钟前
使用n8n工作流自动化生成每日科技新闻速览:告别信息过载,拥抱智能阅读
前端
掘金一周1 小时前
一个前端工程师的年度作品:从零开发媲美商业级应用的后台管理系统 | 掘金一周 10.23
前端·人工智能·后端