兄弟们,2025年了!求求你优化一下图片加载吧

通过HTML+CSS设置

原理

  1. 在图片外层设置一个背景图作为默认图片,避免加载的时候展示空白页。
  2. 设置img标签加载完成的时候才展示,并且img标签不设宽高,避免样式问题。

代码

html 复制代码
<style>
  .image-container {
    width: 300px;
    height: 200px;
    background: url('default-image.jpg') no-repeat center center;
  }
  .image-container img {
    width: 100%;
    height: 100%;
    display: none; /* 默认隐藏 */
    object-fit: cover;
  }
</style>

<div class="image-container">
  <img src="target-image.jpg" onload="this.style.display='block';">
</div>

问题

  1. 页面上所有的图片会全部加载。
  2. 图片加载报错以后页面展示错误内容。
  3. 图片加载完成过程中可能出现"闪烁"现象。

【进阶方案】使用图片懒加载方案设置

原理

  1. 在图片外层设置一个背景图作为默认图片。
  2. 给图片设置 data-src 属性作为图片 url 地址。
  3. 检测当DOM加载完成后,图片是否进入用户可见区域,将 data-src 赋给 src,并移除 data-src 避免重复加载。
  4. 对加载报错的图片另行处理。

代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <style>
        .product-image {
            width: 300px;
            height: 200px;
            background: url('default-image.jpg') no-repeat center center;
            background-size: cover;
            display: inline-block;
        }
        .product-image img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: none; /* 默认不显示 */
        }
        .product-image img.error {
            display: block;
            background: url('error-image.jpg') no-repeat center center;
            background-size: cover;
        }
    </style>
</head>
<body>

<div class="product-image">
    <img data-src="target-image.jpg" alt="Product Image" 
         onload="this.style.display='block'; this.parentNode.style.backgroundImage='none';"
         onerror="this.classList.add('error'); this.src=''; this.parentNode.style.backgroundImage='none';">
</div>

<script>
    // 确保脚本仅在DOM完全加载后执行,避免尝试操作尚未加载的DOM元素。
    document.addEventListener("DOMContentLoaded", function() {
        // 获取全部需要懒加载的图片DOM
        var lazyImages = [].slice.call(document.querySelectorAll("img[data-src]"));
        // 判断浏览器是否支持 IntersectionObserver API
        if ("IntersectionObserver" in window) {
            // 对进入可视区域的Img标签进行"观察"
            let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
                // 对进入可视区域的Img标签进行 data-src 的替换&删除
                entries.forEach(function(entry) {
                    if (entry.isIntersecting) {
                        let lazyImage = entry.target;
                        lazyImage.src = lazyImage.dataset.src;
                        lazyImage.removeAttribute("data-src");
                        // 对修改完成的元素取消"观察"
                        lazyImageObserver.unobserve(lazyImage);
                    }
                });
            });
            // 对所有Img标签元素取消观察
            lazyImages.forEach(function(image) {
                lazyImageObserver.observe(image);
            });
        } else {
            // 如果浏览器不支持,则退回到直接使用 src
            lazyImages.forEach(function(img) {
                img.src = img.getAttribute("data-src");
                img.removeAttribute("data-src");
            });
        }
    });
</script>

</body>
</html>

【Vue方案】使用 vue-lazyload 插件

代码

shell 复制代码
# 安装 vue-lazyload 插件
npm install vue-lazyload
vue 复制代码
<template>
    <div class="product-image" :style="{backgroundImage: `url(${placeholder})`}">
        <img v-lazy="imageSrc"
             @load="onImageLoad"
             @error="onImageError"
             :class="{'error': isError}"
             alt="Product Image"/>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                imageSrc: 'target-image.jpg', // 图片的真实地址
                placeholder: 'default-image.jpg', // 默认占位图地址
                isError: false, // 标记图片是否加载失败
            };
        },
        methods: {
            onImageLoad(event) {
                // 当图片成功加载时隐藏背景图
                event.target.parentElement.style.backgroundImage = 'none';
            },
            onImageError(event) {
                // 当图片加载失败时标记isError为true,并设置错误图片
                this.isError = true;
                event.target.src = ''; // 清空src属性避免重复尝试加载
                event.target.parentElement.style.backgroundImage = 'none'; // 隐藏背景图
            }
        }
    };
</script>

<style scoped>
    .product-image {
        width: 300px;
        height: 200px;
        background-size: cover;
        background-position: center;
        display: inline-block;
    }
    .product-image img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: none; /* 默认不显示 */
    }
    .product-image img.error {
        display: block;
        background: url('error-image.jpg') no-repeat center center;
        background-size: cover;
    }
</style>

总结

使用懒加载图片方案能最大程度上优化系统体验,但是超大图片仍然存在加载时间过长的问题。并且页面加载效果需要进一步修改,以保证图片加载完成展示时不至于出现视觉上较大的"跳跃感"。

如果是商品类网站图片上还包含大量的 alt 信息,对于SEO有一定意义。而且可以利用浏览器缓存机制来存储已加载的图片资源,对于访问重复页面的性能提升非常大。

后续考虑继续深化一下,进一步了解一下图片压缩,webp等图片优化技术。

埋坑!

相关推荐
saber_andlibert5 小时前
TCMalloc底层实现
java·前端·网络
逍遥德5 小时前
如何学编程之01.理论篇.如何通过阅读代码来提高自己的编程能力?
前端·后端·程序人生·重构·软件构建·代码规范
冻感糕人~5 小时前
【珍藏必备】ReAct框架实战指南:从零开始构建AI智能体,让大模型学会思考与行动
java·前端·人工智能·react.js·大模型·就业·大模型学习
程序员agions5 小时前
2026年,“配置工程师“终于死绝了
前端·程序人生
alice--小文子6 小时前
cursor-mcp工具使用
java·服务器·前端
晚霞的不甘6 小时前
揭秘 CANN 内存管理:如何让大模型在小设备上“轻装上阵”?
前端·数据库·经验分享·flutter·3d
小迷糊的学习记录6 小时前
0.1 + 0.2 不等于 0.3
前端·javascript·面试
空&白6 小时前
vue暗黑模式
javascript·vue.js
梦帮科技6 小时前
Node.js配置生成器CLI工具开发实战
前端·人工智能·windows·前端框架·node.js·json
VT.馒头7 小时前
【力扣】2695. 包装数组
前端·javascript·算法·leetcode·职场和发展·typescript