当前位置: 首页 > article >正文

如何实现图片懒加载,原生 + React 实现方式

前言

有时候列表存在许多图片,那么一次性加载会阻塞 http 请求,为了避免在可视窗口之外的元素进行不必要的图片加载,可以尝试使用懒加载进行优化。懒加载可以显著提高页面加载性能,特别是当页面包含大量图片时。为了实现延迟加载图片(也称为懒加载),可以使用 JavaScript 和 Intersection Observer API。

实现

步骤

  1. HTML 结构:为每个图片元素设置一个占位符,并使用 data-src 属性存储实际的图片 URL。
  2. CSS 样式:设置图片占位符的样式。
  3. JavaScript:使用 Intersection Observer API 监控图片元素,当图片元素进入视口时,加载实际的图片。

代码示例

HTML 结构
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Lazy Load Images</title>
  <style>
    .placeholder {
      width: 100%;
      height: 200px;
      background-color: #f0f0f0;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #ccc;
    }
  </style>
</head>
<body>
  <h1>Lazy Load Images Example</h1>
  <div class="image-container">
    <img class="lazy" data-src="image1.jpg" alt="Image 1" class="placeholder">
    <img class="lazy" data-src="image2.jpg" alt="Image 2" class="placeholder">
    <img class="lazy" data-src="image3.jpg" alt="Image 3" class="placeholder">
    <!-- 添加更多图片 -->
  </div>

  <script>
    document.addEventListener("DOMContentLoaded", function() {
      const lazyImages = document.querySelectorAll('img.lazy');

      if ('IntersectionObserver' in window) {
        const lazyImageObserver = new IntersectionObserver(function(entries, observer) {
          entries.forEach(function(entry) {
            if (entry.isIntersecting) {
              const lazyImage = entry.target;
              lazyImage.src = lazyImage.dataset.src;
              lazyImage.classList.remove('lazy');
              lazyImageObserver.unobserve(lazyImage);
            }
          });
        });

        lazyImages.forEach(function(lazyImage) {
          lazyImageObserver.observe(lazyImage);
        });
      } else {
        // Fallback for browsers that do not support IntersectionObserver
        let lazyLoadThrottleTimeout;
        function lazyLoad() {
          if (lazyLoadThrottleTimeout) {
            clearTimeout(lazyLoadThrottleTimeout);
          }

          lazyLoadThrottleTimeout = setTimeout(function() {
            const scrollTop = window.pageYOffset;
            lazyImages.forEach(function(img) {
              if (img.offsetTop < (window.innerHeight + scrollTop)) {
                img.src = img.dataset.src;
                img.classList.remove('lazy');
              }
            });
            if (lazyImages.length == 0) {
              document.removeEventListener("scroll", lazyLoad);
              window.removeEventListener("resize", lazyLoad);
              window.removeEventListener("orientationChange", lazyLoad);
            }
          }, 20);
        }

        document.addEventListener("scroll", lazyLoad);
        window.addEventListener("resize", lazyLoad);
        window.addEventListener("orientationChange", lazyLoad);
      }
    });
  </script>
</body>
</html>
解释
  1. HTML 结构
    • 使用 data-src 属性存储实际的图片 URL。
    • 使用 class="lazy" 标记需要懒加载的图片。
  2. CSS 样式
    • 设置图片占位符的样式,确保在图片加载前显示占位符。
  3. JavaScript
    • 使用 IntersectionObserver 监控图片元素,当图片元素进入视口时,加载实际的图片。
    • 如果浏览器不支持 IntersectionObserver,使用滚动事件和节流函数实现懒加载。

React 代码实例

代码结构
  1. 创建 React 组件
import React, { useEffect, useRef } from 'react';
import './App.css';

const LazyImage = ({ src, alt }) => {
  const imgRef = useRef();

  useEffect(() => {
    const imgElement = imgRef.current;

    const handleIntersection = (entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.classList.remove('lazy');
          observer.unobserve(lazyImage);
        }
      });
    };

    const observer = new IntersectionObserver(handleIntersection, {
      root: null, // 使用视口作为根
      rootMargin: '0px',
      threshold: 0.1 // 当至少 10% 的图片进入视口时触发
    });

    if (imgElement) {
      observer.observe(imgElement);
    }

    return () => {
      if (imgElement) {
        observer.unobserve(imgElement);
      }
    };
  }, []);

  return <img ref={imgRef} data-src={src} alt={alt} className="lazy placeholder" />;
};

const App = () => {
  return (
    <div className="App">
      <h1>Lazy Load Images Example</h1>
      <div className="image-container">
        <LazyImage src="https://via.placeholder.com/300" alt="Image 1" />
        <LazyImage src="https://via.placeholder.com/300" alt="Image 2" />
        <LazyImage src="https://via.placeholder.com/300" alt="Image 3" />
        {/* 添加更多图片 */}
      </div>
    </div>
  );
};

export default App;
  1. 添加 CSS 样式
    在 App.css 文件中添加以下样式:
.placeholder {
  width: 100%;
  height: 200px;
  background-color: #f0f0f0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ccc;
}
解释
  1. LazyImage 组件
    • 使用 useRef 获取图片元素的引用。
    • 使用 useEffect 在组件挂载时创建 IntersectionObserver 实例,并监控图片元素。
    • 当图片元素进入视口时,加载实际的图片,并取消对该图片元素的监控。
  2. App 组件
    • 渲染多个 LazyImage 组件,每个组件对应一张需要懒加载的图片。
  3. CSS 样式
    • 设置图片占位符的样式,确保在图片加载前显示占位符。
调试步骤
  1. 检查图片元素是否被正确观察
    • 在 useEffect 中添加 console.log(imgElement),确保图片元素被正确获取。
  2. 检查 IntersectionObserver 的回调
    • 在 handleIntersection 函数中添加 console.log(entries),确保回调函数被正确调用。
  3. 检查图片元素是否进入视口
    • 确保页面布局正确,图片元素确实进入了视口。

兼容性

  • IntersectionObserver 是现代浏览器支持的 API,如果需要兼容旧版浏览器,可以使用滚动事件和节流函数作为回退方案。

这样,当用户滚动页面时,只有进入视口的图片才会被加载,从而提高页面的加载性能。

总结

但这样不可避免的会存在一定视觉效果上的体验缺失,在页面滚动特别快速时,由于浏览器来不及绘制刚刚进入视图的元素,便会导致出现短暂的白屏现象。这便需要在开发过程中,去做出一定地取舍。


http://www.kler.cn/a/374998.html

相关文章:

  • uniapp 文本转语音
  • 【VScode】第三方GPT编程工具-CodeMoss安装教程
  • 【Golang 面试题】每日 3 题(六)
  • 【接口自动化连载】使用yaml配置文件自动生成接口case
  • Django 模型中使用选择(choices):全面指南
  • EasyExcel 模板+公式填充
  • 数据库管理系统的ACID都各自是什么?
  • 遗传算法:AI 借鉴生物进化的优化方法
  • HTML练习题 :新闻列表 包含盒子模型,内边距,外边距,鼠标悬停
  • 数据结构模拟题[二]
  • scrapy爬取名人名言
  • 安卓基础001
  • .NET Core WebApi第4讲:控制器、路由
  • LeetCode每日一题3165---不包含相邻元素的子序列的最大和
  • 扩展el-table,实现当showOverflowTooltip时,鼠标可移入tooltip功能
  • 一个免费开源自托管的机器翻译项目,支持API接口
  • 建筑行业知识库搭建:好处、方法与注意事项
  • Chrome和Firefox哪款浏览器的密码管理更安全
  • C++第十讲:继承
  • LeetCode --- 421周赛
  • linux开机自启动三种方式
  • PySpark的使用
  • 一、Go语言快速入门之基础语法
  • python的socket库的基本使用总目录
  • 大语言模型推理源码解读(基于llama3模型:来源github)
  • SpringBoot旋律线:Web音乐网站构建