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

埋坑!

相关推荐
IT_陈寒4 小时前
Java性能优化:从这8个关键指标开始,让你的应用提速50%
前端·人工智能·后端
天生我材必有用_吴用4 小时前
Vue3+Node.js 实现大文件上传:断点续传、秒传、分片上传完整教程(含源码)
前端
摸鱼的春哥5 小时前
前端程序员最讨厌的10件事
前端·javascript·后端
牧羊狼的狼9 小时前
React 中的 HOC 和 Hooks
前端·javascript·react.js·hooks·高阶组件·hoc
知识分享小能手10 小时前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
魔云连洲10 小时前
深入解析:Vue与React的异步批处理更新机制
前端·vue.js·react.js
mCell11 小时前
JavaScript 的多线程能力:Worker
前端·javascript·浏览器
超级无敌攻城狮12 小时前
3 分钟学会!波浪文字动画超详细教程,从 0 到 1 实现「思考中 / 加载中」高级效果
前端
excel13 小时前
用 TensorFlow.js Node 实现猫图像识别(教学版逐步分解)
前端
前端工作日常13 小时前
我学习到的Vue2.6的prop修饰符
vue.js