兄弟们,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等图片优化技术。

埋坑!

相关推荐
麻芝汤圆22 分钟前
MapReduce 入门实战:WordCount 程序
大数据·前端·javascript·ajax·spark·mapreduce
juruiyuan1112 小时前
FFmpeg3.4 libavcodec协议框架增加新的decode协议
前端
Peter 谭3 小时前
React Hooks 实现原理深度解析:从基础到源码级理解
前端·javascript·react.js·前端框架·ecmascript
LuckyLay4 小时前
React百日学习计划——Deepseek版
前端·学习·react.js
gxn_mmf4 小时前
典籍知识问答重新生成和消息修改Bug修改
前端·bug
hj10434 小时前
【fastadmin开发实战】在前端页面中使用bootstraptable以及表格中实现文件上传
前端
乌夷4 小时前
axios结合AbortController取消文件上传
开发语言·前端·javascript
晓晓莺歌5 小时前
图片的require问题
前端
码农黛兮_465 小时前
CSS3 基础知识、原理及与CSS的区别
前端·css·css3
水银嘻嘻5 小时前
web 自动化之 Unittest 四大组件
运维·前端·自动化