通过HTML+CSS设置
原理
- 在图片外层设置一个背景图作为默认图片,避免加载的时候展示空白页。
- 设置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>
问题
- 页面上所有的图片会全部加载。
- 图片加载报错以后页面展示错误内容。
- 图片加载完成过程中可能出现"闪烁"现象。
【进阶方案】使用图片懒加载方案设置
原理
- 在图片外层设置一个背景图作为默认图片。
- 给图片设置 data-src 属性作为图片 url 地址。
- 检测当DOM加载完成后,图片是否进入用户可见区域,将 data-src 赋给 src,并移除 data-src 避免重复加载。
- 对加载报错的图片另行处理。
代码
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等图片优化技术。
埋坑!