图片懒加载之React + Intersection Observer API - 交叉观察器实现懒加载

React,自定义hook,Intersection Observer API实现图片的懒加载。

之前方法是通过element.getBoundingClientRect()来获取元素距离视口位置然后监听scroll事件(文章链接),判断元素是否进入视口从而来实现懒加载,因为用到了scroll的监听事件,因此频繁触发、调用可能会造成性能问题。这种方法的优点是兼容性较好,但检测方法却极其怪异且不优雅,因此官方就提出了Intersection Observer API,用来高效解决图片懒加载、内容无限滚动、触底加载、两个元素是否相交等场景。

什么是Intersection Observer API 

IntersectionObserver接口(从属于 Intersection Observer API)提供了一种异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法。其祖先元素或视口被称为根(root)。

当一个 IntersectionObserver对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦 IntersectionObserver被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。

以上出自MDN官方文档描述。

故我们需要观察的元素被称为目标元素(target),设备视口或我们指定的元素视口的边界框我们称它为根元素(root),简称为 。

IntersectionObserver翻译过来叫做 “交叉观察器”,因为判断元素是否可见的本质就是看目标元素是否与根元素或视口产生了交叉。

构造函数:

IntersectionObserver();

创建一个IntersectionObserver.observe对象,当其监听到目标元素的可见部分(的比例)超过了一个或多个阈值(threshold)时,会执行指定的回调函数。 

实例方法:

    IntersectionObserver.observe(); 使IntersectionObserver开始监听一个目标元素。

    IntersectionObserver.unobserve();使IntersectionObserver停止监听特定目标元素。

    IntersectionObserver.disconnect(); 使IntersectionObserver对象停止监听目标。

 接下我们进入实践,src目录下添加hook文件夹,创建一个自定义hook组件。

请求接口,拿到数据然后渲染视图,数据遍历时我们将图片url优先给我们<img>标签的自定属性datasrc,等后边判断可见时再赋值给src使其显示出来。

import React, { useEffect, useState } from 'react'
import { getImages } from '../../api'

export default function NewTestpage() {
    const [images, setImages] = useState([]);

    // 渲染数据接口
    const getPageImage = () => {
        getImages("query").then(res => {
            if (res.status === 200) {
                // console.log(res);
                setImages(res.data);
            }
        })
    }

    useEffect(() => {
        getPageImage();
    }, [])


    return (
        <div>
            <div className="imgBox" style={{ height: "200vh" }}>
                {images.map(item => (
                    <div key={item.name}>
                        <img datasrc={item.url} className='imgEle' alt="" style={{ height: "500px", width: "400px", minHeight: "500px", minWidth: "400px" }} />
                    </div>
                ))}
            </div>
        </div>
    )
}

然后用Intersection Observer API写我们的自定义hook并导出。

import { useEffect } from 'react'

// 声明一个变量 用来接收observer对象
let observer;

// ele为目标元素 watch依赖项
export default function VisibleImages(ele, watch) {

    useEffect(() => {
        const nodes = document.querySelectorAll(ele);
        // 如果目标不为空
        if (nodes && nodes.length) {
            // 创建IntersectionObserver对象 entries为IntersectionObserverEntry对像数组
            observer = new IntersectionObserver((entries) => {
                // console.log(entries);
                entries.forEach(item => {
                    // isIntersecting是一个Boolean值,判断目标元素当前是否可见
                    if (item.isIntersecting) {
                        // 获取到我们自定的img属性 赋值给src 然后停止该目标监听
                        const datasrc = item.target.getAttribute("datasrc");
                        item.target.src = datasrc;
                        observer.unobserve(item.target);
                    }
                })
            })
            // 开始监听目标元素
            nodes.forEach(item => {
                observer.observe(item);
            })
        }

        // 组件注销时 停止对象监听
        return () => {
            if (nodes && nodes.length && observer) {
                observer.disconnect();
            }
        }
    }, watch)
}

将hook引入到我们需要的组件中,然后传参执行,最终为:

import React, { useEffect, useState } from 'react'
import { getImages } from '../../api'
// 引入自定hook
import VisibleImages from '../../hook/VisibleImages';

export default function NewTestpage() {

    const [images, setImages] = useState([]);

    const getPageImage = () => {
        getImages("query").then(res => {
            if (res.status === 200) {
                // console.log(res);
                setImages(res.data);
            }
        })
    }

    // 将监听目标元素类名传入,依赖项为null
    VisibleImages(".imgEle",null);

    useEffect(() => {
        getPageImage();
    }, [])


    return (
        <div>
            <div className="imgBox" style={{ height: "200vh" }}>
                {images.map(item => (
                    <div key={item.name}>
                        <img datasrc={item.url} className='imgEle' alt="" style={{ height: "500px", width: "400px", minHeight: "500px", minWidth: "400px" }} />
                    </div>
                ))}
            </div>
        </div>
    )
}

最后,大功告成!

  • 20
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
React实现列表图片的懒加载,我们可以结合使用 `react-lazyload` 库和 `Intersection Observer API`。以下是基于这两个工具的实现步骤: 1. 首先,安装 `react-lazyload` 库。 ```bash npm install react-lazyload ``` 2. 在列表组件中引入 `react-lazyload` 组件,并使用 `Intersection Observer API` 监听图片是否进入可视区域。 ```jsx import React from 'react'; import LazyLoad from 'react-lazyload'; const ListItem = ({ imageUrl, altText }) => { return ( <LazyLoad> <img src={imageUrl} alt={altText} /> </LazyLoad> ); }; const ListComponent = ({ items }) => { return ( <ul> {items.map((item) => ( <li key={item.id}> <ListItem imageUrl={item.imageUrl} altText={item.altText} /> </li> ))} </ul> ); }; export default ListComponent; ``` 在上述代码中,我们使用 `react-lazyload` 组件包裹了 `<img>` 元素,并将图片的地址和替代文本作为属性传递给子组件 `ListItem`。当图片进入可视区域时,`react-lazyload` 会自动加载图片。 3. 在父组件中使用 `ListComponent`,并传递图片数据给列表组件。 ```jsx import React from 'react'; import ListComponent from './ListComponent'; const App = () => { const items = [ { id: 1, imageUrl: 'image1.jpg', altText: 'Image 1' }, { id: 2, imageUrl: 'image2.jpg', altText: 'Image 2' }, { id: 3, imageUrl: 'image3.jpg', altText: 'Image 3' }, // 更多图片数据 ]; return ( <div> <h1>List of Images</h1> <ListComponent items={items} /> </div> ); }; export default App; ``` 在父组件中,我们创建了一个包含图片数据的数组,并将其传递给列表组件 `ListComponent`。列表组件会根据传递的数据生成相应的图片项。 通过以上步骤,我们可以在 React实现列表图片的懒加载。 `react-lazyload` 库会自动处理图片的加载,只有当图片进入可视区域时才进行加载,从而提升页面性能和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值