这段代码实现了一个图片渐进式加载的效果,先加载小图然后再加载大图,提升用户体验。
- 基本结构:
<!-- 假设的HTML结构 -->
<div class="placeholder" data-large="large-image.jpg">
<img class="img-small" src="small-image.jpg">
</div>
- 代码逻辑解析:
window.onload = function() {
// 获取DOM元素
var placeholder = document.querySelector('.placeholder'), // 容器元素
small = placeholder.querySelector('.img-small') // 小图元素
// 步骤1:加载小图
var img = new Image(); // 创建新的Image对象
img.src = small.src; // 设置图片源
img.onload = function () {
small.classList.add('loaded'); // 小图加载完成后添加loaded类
};
// 步骤2:加载大图
var imgLarge = new Image();
imgLarge.src = placeholder.dataset.large; // 从data-large属性获取大图URL
imgLarge.onload = function () {
imgLarge.classList.add('loaded'); // 大图加载完成后添加loaded类
};
placeholder.appendChild(imgLarge); // 将大图添加到容器中
}
- 工作原理:
- 首先加载体积小的缩略图(模糊或低质量)
- 同时开始加载高质量大图
- 小图加载完成后立即显示,给用户快速反馈
- 大图加载完成后平滑替换小图
- 相关CSS:
.placeholder {
position: relative;
overflow: hidden;
}
.img-small {
/* 初始状态可能是模糊的 */
filter: blur(50px);
transition: opacity .1s ease-in-out;
}
.img-small.loaded {
opacity: 1;
}
.placeholder img:last-child {
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: opacity .3s ease-in-out;
}
.placeholder img:last-child.loaded {
opacity: 1;
}
- 优点:
- 提升用户体验,不会出现空白等待
- 渐进式加载,先显示模糊预览
- 网络慢时效果更明显
- 减少用户等待焦虑
- 使用场景:
- 大图片展示
- 图片列表
- 产品详情页
- 背景图片加载
这种技术被称为"渐进式图片加载"或"模糊加载",类似于Medium网站的图片加载效果。Facebook、Instagram等也使用类似技术来优化图片加载体验。
如何结合React进行简单实现?
import React, { useState, useEffect } from 'react';
const ProgressiveImage = ({ smallSrc, largeSrc, alt, className }) => {
const [smallImageLoaded, setSmallImageLoaded] = useState(false);
const [largeImageLoaded, setLargeImageLoaded] = useState(false);
useEffect(() => {
// Load small image
const smallImage = new Image();
smallImage.src = smallSrc;
smallImage.onload = () => {
setSmallImageLoaded(true);
};
// Load large image
const largeImage = new Image();
largeImage.src = largeSrc;
largeImage.onload = () => {
setLargeImageLoaded(true);
};
}, [smallSrc, largeSrc]);
return (
<div className="relative overflow-hidden">
<img
src={smallSrc}
alt={alt}
className={`
w-full h-full
${smallImageLoaded ? 'opacity-100' : 'opacity-0'}
${largeImageLoaded ? 'scale-110 blur-2xl' : 'scale-100 blur-none'}
transition-all duration-200
${className || ''}
`}
/>
{largeImageLoaded && (
<img
src={largeSrc}
alt={alt}
className={`
absolute top-0 left-0
w-full h-full
${largeImageLoaded ? 'opacity-100' : 'opacity-0'}
transition-opacity duration-300
${className || ''}
`}
/>
)}
</div>
);
};
export default ProgressiveImage;