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

埋坑!

相关推荐
天天扭码24 分钟前
面试官:算法题”除自身以外数组的乘积“ 我:😄 面试官:不能用除法 我:😓
前端·算法·面试
小小小小宇27 分钟前
十万字JS不良实践总结(逼疯审核版)
前端
喝拿铁写前端30 分钟前
从列表页到规则引擎:一个组件封装过程中的前端认知进阶
前端·vue.js·架构
小小小小宇1 小时前
React Lanes(泳道)机制
前端
zhangxingchao1 小时前
Jetpack Compose 之 Modifier(上)
前端
龙萌酱1 小时前
力扣每日打卡17 49. 字母异位词分组 (中等)
前端·javascript·算法·leetcode
工呈士1 小时前
HTML与Web性能优化
前端·html
秃了才能变得更强1 小时前
React Native 原生模块集成Turbo Modules
前端
旺旺大力包1 小时前
【 React 】重点知识总结 && 快速上手指南
开发语言·前端·react.js
咪库咪库咪2 小时前
使用Fetch api发起请求
前端