React实现图片懒加载的常见方式

 更新时间:2024年01月09日 08:23:49   作者:Mh  
图片懒加载是一种优化网页性能的技术,它允许在用户滚动到图片位置之前延迟加载图片,通过懒加载,可以在用户需要查看图片时才加载图片,避免了不必要的图片加载,本文给大家介绍了React实现图片懒加载的常见方式,需要的朋友可以参考下

前言

图片懒加载是一种优化网页性能的技术,它允许在用户滚动到图片位置之前延迟加载图片。通过懒加载,可以在用户需要查看图片时才加载图片,避免了不必要的图片加载,从而提高了网页的加载速度和用户体验。

方案一

实现思路

在说明思路之前,先了解几个常见的视图属性。

  • clientHeight:可视区域的高度,对应的也就是下图中的滚动区域。
  • scrollTop:滚动条滚动的高度,它指的是内容区的顶部到可视区域顶部的距离。
  • offsetTop:元素到offsetParent顶部的距离。
  • offsetParent:距离元素最近的一个具有定位的祖宗元素(relative,absolute,fixed),若祖宗都不符合条件,offsetParent为body。

图解:

根据上面的图解可知,当图片的滚动条滚动的高度加上可视区域的高度大于当前的图片的offsetTop,那么说明图片正在进入可视区域。这个时候便可以加载当前图片。

第一步

模拟后台返回的图片url,遍历产生一个url集合,用于后面的懒加载使用。

const imgUrls = (num = 10) => {
  const urls = [];
  for (let i = 0; i < num; i++) {
    const url = `https://robohash.org/${i}.png`;
    urls.push(url);
  }
  return urls;
};

第二步

遍历图片url集合,渲染100张loading图片,css部分省略。

    <div className={styles['box-one']} ref={scrollRef}>
      {imgUrls(100).map((item) => {
        return <img data-src={item} key={item} src={loadingUrl} alt="" />;
      })}
    </div>

效果预览

第三步

监听容器的滚动事件,当容器滚动时计算容器的高度加上滚动条的高度大于当前图片的offsetTop时加载当前的图片。完整代码如下:

import loadingUrl from '@/assets/imgs/loading.jpg';
import { useEffect, useRef } from 'react';
import styles from '../index.less';

// 图片url
const imgUrls = (num = 10) => {
  const urls = [];
  for (let i = 0; i < num; i++) {
    const url = `https://robohash.org/${i}.png`;
    urls.push(url);
  }
  return urls;
};

const LazyLoading = () => {
  const scrollRef = useRef({} as any);

  // 滚动事件
  const changeScroll = () => {
    const clientHeight = scrollRef?.current.clientHeight; //可视区域高度
    const scrollTop = scrollRef?.current.scrollTop; //滚动条滚动高度
    const childNodes = scrollRef?.current.childNodes; // 获取所有图片集合

    for (let j = 0; j < childNodes.length; j++) {
      const element = childNodes[j];
      if (scrollTop + clientHeight > element.offsetTop) {
        element.src = element.getAttribute('data-src'); // 替换当前的src
      }
    }
  };

  useEffect(() => {
    changeScroll(); // 第一次渲染的时候替换loading图片
  }, []);

  return (
    <div className={styles['box-one']} ref={scrollRef} onScroll={changeScroll}>
      {imgUrls(100).map((item) => {
        return <img data-src={item} key={item} src={loadingUrl} alt="" />;
      })}
    </div>
  );
};

export default LazyLoading;

效果预览

方案二

实现思路

方案二的实现思路利用浏览器提供的 IntersectionObserver API实现。IntersectionObserver API提供了一种方便的方式来监视目标元素和其祖先元素或视窗之间的交叉状态变化。当目标元素进入或离开视口时,可以触发回调函数,进行相应的操作。它的原理是通过注册一个回调函数来观察特定元素的交叉状态变化,并在满足条件时执行相应的操作。

使用 IntersectionObserver API非常简单,可以通过创建一个 IntersectionObserver 实例,并传入回调函数和选项对象来实现。回调函数会在目标元素的交叉状态发生变化时被调用,并接收一个参数,包含有关交叉状态的信息。

实现完整代码

import loadingUrl from '@/assets/imgs/loading.jpg';
import styles from '../index.less';
import React, { useRef, useEffect, useState } from 'react';
// 图片url
const imgUrls = (num = 10) => {
  const urls = [];
  for (let i = 0; i < num; i++) {
    const url = `https://robohash.org/${i}.png`;
    urls.push(url);
  }
  return urls;
};

const LazyLoadImage = ({ src, alt }) => {
  const [imageSrc, setImageSrc] = useState(loadingUrl);
  const imgRef = useRef(null as any);

  useEffect(() => {
    let observer: IntersectionObserver;
    if (imgRef.current) {
      // 创建IntersectionObserver实例
      observer = new IntersectionObserver(
        ([entry]) => {
          // 当图片进入可视区域时,设置图片地址进行加载
          if (entry.isIntersecting) {
            setImageSrc(src);
            observer.unobserve(imgRef.current);
          }
        },
        {
          rootMargin: '0px 0px 200px 0px', // 可视区域的上边距设置为200px
        },
      );
      observer.observe(imgRef.current); //开始观察目标元素
    }
    return () => {
      if (observer && observer.unobserve) {
        observer.unobserve(imgRef.current);
      }
    };
  }, [src]);

  return <img ref={imgRef} src={imageSrc} alt={alt} />;
};

const LazyLoading = () => {
  return (
    <div className={styles['box-two']}>
      {imgUrls(100).map((item) => {
        return <LazyLoadImage src={item} alt="lazy load image" />;
      })}
    </div>
  );
};

export default LazyLoading;

实现效果

注意事项

在初始化的时候,需要给imageSrc设置一个初始化的loading地址,如果没有的话,初始化的时候会加载多张图片。

方案三

实现思路

利用react的懒加载库react-lazyload,在使用之前需要先安装 yarn add react-lazyload,这里介绍几个它的常见属性:

  • scrollContainer: 指定的滚动的区域,默认值是undefined,如果没有指定默认是窗口的视图作为滚动区域。
  • offset: 元素距离视口顶部的距离,当达到这个距离时,元素将被加载。
  • scroll: 是否监听滚动
  • height: 渲染元素的占位符的高度。
  • overflow : 如果溢出容器,延迟加载组件

代码实现

因为这里实现的图片懒加载是局部懒加载,所以需要指定 scrollContainerscrollContainer 的值DOM对象。在实现的过程中,同时需要设置overflow为true,以及height的值。

import react, { useRef, useEffect } from 'react';
import LazyLoad from 'react-lazyload';
import styles from '../index.less';

// 图片url
const imgUrls = (num = 10) => {
  const urls = [];
  for (let i = 0; i < num; i++) {
    const url = `https://robohash.org/${i}.png`;
    urls.push(url);
  }
  return urls;
};

const LazyLoading = () => {
  const scrollRef = useRef({} as any);

  return (
    <div className={styles['box-three']} ref={scrollRef}>
      {imgUrls(100).map((item) => {
        return (
          <LazyLoad
            height={200}
            overflow={true}
            offset={0}
            key={item}
            scroll={true}
            scrollContainer={scrollRef.current} // DOM
          >
            <img src={item} alt="" />
          </LazyLoad>
        );
      })}
    </div>
  );
};

export default LazyLoading;

实现效果

以上就是React实现图片懒加载的常见方式的详细内容,更多关于React图片懒加载的资料请关注脚本之家其它相关文章!

相关文章

  • React路由鉴权的实现方法

    React路由鉴权的实现方法

    这篇文章主要介绍了React路由鉴权的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • React从Class方式转Hooks详解

    React从Class方式转Hooks详解

    这篇文章主要介绍了React从Class方式转Hooks详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-09-09
  • 一文搞懂 React 18 中的 useTransition() 与 useDeferredValue()

    一文搞懂 React 18 中的 useTransition() 与 useDeferredValue()

    这篇文章主要介绍了一文搞懂 React 18 中的 useTransition()与useDeferredValue(),文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • react render的原理及触发时机说明

    react render的原理及触发时机说明

    这篇文章主要介绍了react render的原理及触发时机说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • 解决React报错React.Children.only expected to receive single React element child

    解决React报错React.Children.only expected to rece

    这篇文章主要为大家介绍了React报错React.Children.only expected to receive single React element child分析解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • react中Suspense的使用详解

    react中Suspense的使用详解

    这篇文章主要介绍了react中Suspense的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 在react中对less实现scoped配置方式

    在react中对less实现scoped配置方式

    这篇文章主要介绍了在react中对less实现scoped配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • React实现合成事件的源码分析

    React实现合成事件的源码分析

    React 中的事件,是对原生事件的封装,叫做合成事件。抽象出一层合成事件,是为了做兼容,抹平不同浏览器之间的差异。本文将从事件绑定和事件触发角度,带大家解读下源码,感兴趣的可以了解一下
    2022-12-12
  • React hook超详细教程

    React hook超详细教程

    Hook是React16.8的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性,这篇文章主要介绍了React hook的使用
    2022-10-10
  • react map使用方法实例详解

    react map使用方法实例详解

    map()方法是在React中常用的数组处理方法之一,可以用于遍历数组、生成组件列表以及进行数据转换等操作,通过合理运用map()方法,可以更灵活地处理和展示数据,下面给大家讲解react map使用方法,感兴趣的朋友一起看看吧
    2023-10-10

最新评论