• 如何实现图片懒加载,原生 + 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 Imagestitle>
      <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 Exampleh1>
      <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,如果需要兼容旧版浏览器,可以使用滚动事件和节流函数作为回退方案。

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

    总结

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

  • 相关阅读:
    2022年找工作确实不易
    趣味中秋,用动画字符来贺岁佳节
    基于JAVA框架的报修系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    类的构造函数执行顺序
    java循环语句
    在国内通过 kubeadm 部署 k8s (基于 openEuler 22.03)
    Android WIFI工具类 特别兼容Android12
    点击化学(Click chemistry) 叠氮-PEG4-NHS/Biotin-PEG-N3/Azid/DBCO-EPG-NHS/DBCO-NH2
    自定义GPT已经出现,并将影响人工智能的一切,做好被挑战的准备了吗?
    gorm的使用(持续更新)
  • 原文地址:https://blog.csdn.net/GuoJiangweigege/article/details/143304958