首页 > 其他分享 >IntersectionObserver 实现图片懒加载、列表无限滚动等功能

IntersectionObserver 实现图片懒加载、列表无限滚动等功能

时间:2023-08-24 09:33:53浏览次数:35  
标签:const target observer 元素 列表 IntersectionObserver 目标 加载

过去,要检测一个元素是否可见或者两个元素是否相交并不容易,比如实现图片懒加载、内容无限滚动等功能时,都需要通过​getBoundingClientRect()​写大量的逻辑计算或者依靠scroll事件监听等性能很差方式来实现。

现在,依靠IntersectionObserver(交叉观察器)我们能非常便捷且高效的实现上述功能。
其实就是观察一个元素,当他出现的时候进行某些操作,比如无限滚动的实现,我们想要无限滚动的列表的最后一个元素,他出现我们就给列表增加
元素把他挤到后面,这样这个元素就看不到了,这样就可以继续滚动.

Intersection Observer API - Web API 接口参考 | MDN
IntersectionObserver API 使用教程 - 阮一峰的网络日志

一、api

// 创建实例
const observer = new IntersectionObserver(callback, option);
 
// 开始观察element1
observer.observe(element1);
 
// 开始观察element2
observer.observe(element2);
 
// 停止观察
observer.unobserve(element);
 
// 关闭观察器
observer.disconnect();

IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。

构造函数的返回值是一个观察器实例。实例的observe方法可以指定观察哪个 DOM 节点,如果需要观察多个DOM节点可以多次添加observe方法。

//初始化一个实例
var observer = new IntersectionObserver(changes => {
    for (const change of changes) {
        console.log(change.time);
        // 当可视状态变化时,状态发送改变的时间戳
        // 对比时间为,实例化的时间,
        // 比如,值为1000时,表示在IntersectionObserver实例化的1秒钟之后,触发该元素的可视性变化

        console.log(change.rootBounds);
        // 根元素的矩形区域信息,即为getBoundingClientRect方法返回的值

        console.log(change.boundingClientRect);
        // target.boundingClientRect()
        // 目标元素的矩形区域的信息

        console.log(change.intersectionRect);
        // 目标元素与视口(或根元素)的交叉区域的信息

        console.log(change.intersectionRatio);
        // 目标元素的可见比例,即intersectionRect占boundingClientRect的比例,
        // 完全可见时为1,完全不可见时小于等于0

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

    }
}, {});

// 对元素target添加监听,当target元素变化时,就会触发上述的回调
observer.observe(target);

// 移除一个监听,移除之后,target元素的可视区域变化,将不再触发前面的回调函数
observer.unobserve(target);

// 停止所有的监听
observer.disconnect();

二、callback参数

当以下情况发生时会调用回调函数:

  • Observer 第一次监听目标元素的时候
  • 每当目标元素与设备视窗或者其他指定元素发生交集的时候执行
    image

callback函数的参数(entries)是一个数组,每个成员都是一个IntersectionObserverEntry对象。举例来说,如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员。

每个IntersectionObserverEntry对象属性含义如下:

  • boundingClientRect:目标元素的矩形区域的信息
  • intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
  • intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
  • rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
  • isIntersecting:目标元素是否与视口(或根元素)交叉
  • isVisible:并未查阅到相关资料,且经过测试其并不会发生变化
  • target:被观察的目标元素,是一个 DOM 节点对象
  • time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒

三、Option对象

IntersectionObserver构造函数的第二个参数是一个配置对象。它可以设置以下属性。

root:指定根元素,用于检查目标的可见性。必须是目标元素的父级元素。如果未指定或者为null,则默认为浏览器视窗。
rootMargin:根元素的外边距,类似于 CSS 中的margin属性,比如 "10px 20px 30px 40px" (top、right、bottom、left)。如果有指定 root 参数,则 rootMargin 也可以使用百分比来取值。该属性值是用作 root 元素和 target 发生交集时候的计算交集的区域范围,使用该属性可以控制 root 元素每一边的收缩或者扩张。默认值为四个边距全是 0。
threshold:目标元素与根元素的交叉比例,可以是单一的 number 也可以是 number 数组,比如,[0, 0.25, 0.5, 0.75, 1]就表示当目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。

四、注意事项

  • IntersectionObserver API 是异步的,不随着目标元素的滚动同步触发。
  • 注册的回调函数将会在主线程中被执行,所以该函数执行速度要尽可能的快。如果有一些耗时的操作需要执行,建议使用 Window.requestIdleCallback() 方法。

五、无限滚动

主要就是观察

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>IntersectionObserver</title>
</head>
<style>
    *{
        padding:0;
        margin:0;
    }
    .box{
        background:#faecd8;
        width:600px;
        height:600px;
        overflow: scroll;
        font-size:24px;
        text-align: center;
    }
</style>
<body>
    <div class="box">
        <div id="container"></div>
        <div id="loadMore">加载中...</div>
    </div>
</body>
<script>
const container = document.querySelector('#container');
const loadMore = document.querySelector('#loadMore');
let index = 0;

//批量添加元素
const loadItems = (count) => {
    [...Array(count).keys()].forEach((key) => {
        //当超过100时停止所有观察
        if(index == 100){
            observer.disconnect();
            return;
        }
        const p = document.createElement('P');
        p.innerHTML = `${key + index}`;
        container.appendChild(p)

    })
    index += count;
}

//初始化一个观察实例
const observer = new IntersectionObserver((entries) => {
    //目标元素余市口交叉则显示true,则添加元素
    entries.forEach((entry) => {
        if (entry.isIntersecting) {
            loadItems(20);
        }
    })
},{});

//开始观察
observer.observe(loadMore);
</script>
</html>

标签:const,target,observer,元素,列表,IntersectionObserver,目标,加载
From: https://www.cnblogs.com/tn666/p/17653285.html

相关文章

  • plutosdr通过uboot单独加载bit文件
    导出bit文件,修改uEnv.txt文件,修改bitstream_image为自己的bit文件,如system_top.bit,并增加两行:bitstream_image=system_top.bitmmc_loadbit_fat=echoLoadingbitstream${bitstream_image}fromSDtoRAM...&&mmcinfo&&fatloadmmc0${loadbit_addr}${bitstream_imag......
  • 2023演练重点漏洞关注列表
    ......
  • java-将列表格式化成json字符串
    List<String>list=newArrayList<>();list.add("{'county':'china','age':18}");list.add("{'county':'japan','age':28}");......
  • Python列表推导式
    int_list=range(1,55,2)print(list(int_list))结果:[1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53]int_list=range(1,55,2)print([str(x)forxinint_list])结果:['1','3',&......
  • 懒加载
    首先我们先搭建好页面:<style>*{padding:0%;margin:0%;}.containimg{width:600px;height:400px;}ul{list-style:none;}li{display:inline-block;}</style>&l......
  • Lnton羚通视频算法算力云平台【PyTorch】教程:学习基础知识如何保存和加载模型
    保存和加载模型是指将训练好的神经网络模型保存到文件中,以便在需要时重新加载该模型进行预测、推断或继续训练。保存模型的过程是将模型的参数和其他相关信息(如优化器状态等)保存到文件中。通过保存模型,我们可以在不重新训练的情况下保留模型的状态,方便后续使用。加载模型的过程是从......
  • 【算法】在vue3的ts代码中分组group聚合源数据列表
    有一个IList<any>()对象列表,示例数据为[{id:'1',fieldName:'field1',value:'1'},{id:'1',fieldName:'field2',value:'2'},{id:'2',fieldName:'field1',value:'1'},{id:'2',......
  • Python基础入门学习笔记 011列表:一个打了激素的数组2
    从列表中获取元素•跟数组一样,我们可以通过元素的索引值(index)从列表获取单个元素,注意,列表索引值是从 0 开始的。 从列表删除元素 remove()函数表示从列表中删除某个元素 del()函数也表示从列表中删除某个元素 pop()函数从列表中取出最后一个元素列表分片(Slice)•......
  • Python基础入门学习笔记 012列表:一个打了激素的数组3
    列表的一些常用操作符•比较操作符 •逻辑操作符 •连接操作符 •重复操作符 •成员关系操作符 关于分片“拷贝”概念的补充 >>>dir(list)可查看所有列表的操作函数 count()函数可计算列表中相同元素个数 index()函数可索引列表元素 reverse()将列......
  • 给dbgrid增加日期下拉列表
    在窗口放一个dbgrid,dbdatetimepicker,将dbdatetimepicker设置visible:=false;procedureTForm1.DBGrid1SelectEditor(Sender:TObject;Column:TColumn;varEditor:TWinControl);beginif(DBGrid1.SelectedField.DataType=ftDateTime)or (DBGrid1.SelectedField.DataType......