前端性能优化——懒加载
懒加载是一种优化网页性能的技术,通过在长页面中延迟加载图片等资源,仅在用户滚动到可视区域时才加载。其特点包括减少无用资源加载、提升用户体验、降低服务器压力等。实现方式包括原生JavaScript监听滚动、HTML5的loading="lazy"属性、IntersectionObserver API,以及Vue的vue-lazyload插件。核心原理是将资源路径存储在data属性
1、懒加载的概念
懒加载也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。在比较长的网页或应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可视窗口的那一部分图片数据,这样就浪费了性能。如果使用图片的懒加载就可以解决以上问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,在滚动屏幕时才加载。这样使得网页的加载速度更快,减少了服务器的负载。懒加载适用于图片较多,页面列表较长(长列表)的场景中。
2、懒加载的特点
- 减少无用资源的加载:使用懒加载明显减少了服务器的压力和流量,同时也减小了浏览器的负担。
- 提升用户体验: 如果同时加载较多图片,可能需要等待的时间较长,这样影响了用户体验,而使用懒加载就能大大的提高用户体验。
- 防止加载过多图片而影响其他资源文件的加载 :会影响网站应用的正常使用。
- 按需加载:减少初始页面加载时间,降低服务器和客户端的资源消耗
- 提升页面性能:通过减少初始加载的资源数量,减轻网络带宽的压力,使页面内容更快可见。
- 兼容大多数设备与网络环境:懒加载在任何网络环境下都能有效工作,无论是低速网络还是高速网络都可以受益
- 减少服务器压力:懒加载可以显著减少服务器的负载,因为只有用户实际需要的资源才会被请求。
- 适用多种类型的资源:
- 懒加载不仅适用于图片,还可以应用到视频、脚本、iframe 等各种类型的资源上。
3、懒加载的实现原理
图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会请求图片资源。根据这个原理,我们使用 HTML5 的 data-xxx 属性来储存图片的路径,在需要加载图片的时候,将 data-xxx 中图片的路径赋值给src,这样就实现了图片的按需加载,即懒加载。
注意:data-xxx 中的 xxx 可以自定义,这里我们使用 data-src 来定义。
懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。
3.1、使用原生 JavaScript 实现懒加载:
知识点:
- window.innerHeight 是浏览器可视区的高度
- document.body.scrollTop,document.documentElement.scrollTop 是浏览器滚动的过的距离(前者在一些较旧的浏览器或处于怪异模式(quirks mode)下,
document.body.scrollTop表示页面顶部与可见区域顶部之间的距离,后者浏览器普遍支持)- imgs.offsetTop 是元素顶部距离文档顶部的高度(包括滚动条的距离)
window.pageYOffset是一个只读属性,用来获取当前页面在垂直方向上滚动的像素值。- 图 片 加 载 条 件 : img.offsetTop < window.innerHeight +document.body.scrollTop;
兼容性处理:
为了确保在所有浏览器中都能正确获取页面的垂直滚动距离,通常需要同时检查
document.body.scrollTop和document.documentElement.scrollTop:var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
代码实现
3.2、使用 HTML5 原生 loading="lazy" 属性
现代浏览器已经支持在 <img> 标签上添加 loading="lazy" 属性来实现图片懒加载。
示例:
<img src="example.jpg" alt="example image" loading="lazy" />
浏览器会自动在图片即将出现在视口时加载。
3.3、使用 IntersectionObserver 实现图片懒加载
对于不支持 loading="lazy" 属性的浏览器,可以使用 JavaScript 的 IntersectionObserver API 来实现图片懒加载。
<template>
<div>
<h1>图片懒加载示例</h1>
<div v-if="loading">加载中...</div>
<div v-else>
<div v-for="(image, index) in images" :key="index">
<!-- 使用占位符作为默认图片,并动态绑定数据 -->
<img :data-src="image.url" alt="image.name" class="lazy-image" />
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
images: [], // 存储从后端获取的图片数据
loading: true, // 控制加载状态
observer: null, // 保存 IntersectionObserver 实例
};
},
methods: {
// 从后端获取图片数据
async fetchImages() {
try {
const response = await axios.get('/api/images'); // 获取图片数据的 API
this.images = response.data; // 假设后端返回一个图片对象数组
this.loading = false;
// 在数据加载完后,初始化 IntersectionObserver
this.initObserver();
} catch (error) {
console.error('加载图片数据失败:', error);
this.loading = false;
}
},
// 初始化 IntersectionObserver
initObserver() {
const options = {
root: null, // 使用视口作为根
rootMargin: '0px',
threshold: 0.1, // 当图片 10% 出现在视口中时触发懒加载
};
// 创建 IntersectionObserver 实例
this.observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // 将 data-src 设置为 src,加载图片
this.observer.unobserve(img); // 图片加载后停止观察该图片
}
});
}, options);
// 选择所有需要懒加载的图片
const lazyImages = document.querySelectorAll('.lazy-image');
lazyImages.forEach(image => {
this.observer.observe(image); // 观察每个懒加载图片
});
},
},
mounted() {
// 组件挂载后获取数据
this.fetchImages();
},
beforeDestroy() {
// 清理 observer 防止内存泄漏
if (this.observer) {
this.observer.disconnect();
}
},
};
</script>
<style>
.lazy-image {
width: 100%;
height: auto;
display: block;
margin-bottom: 10px;
background-color: #f3f3f3; /* 占位背景色 */
}
</style>
在这个例子中:
- 每张图片使用
data-src属性保存图片的真实路径。 - 当图片接近或进入视口时,
IntersectionObserver会触发回调,将data-src替换为src,开始加载图片。 - 图片加载完成后,
IntersectionObserver停止观察该图片
3.4使用 Vue 的懒加载插件(如 vue-lazyload)
如果你使用 Vue.js 进行开发,可以直接使用插件如 vue-lazyload 来实现懒加载。
安装 vue-lazyload 插件:
npm install vue-lazyload --save
在vue项目中使用
import Vue from 'vue';
import VueLazyload from 'vue-lazyload';
Vue.use(VueLazyload);
// 或者带有一些默认设置
Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'error.png', // 加载失败时显示的图片
loading: 'loading.gif', // 加载中显示的图片
attempt: 1
});
在模板中使用
<template>
<div>
<h1>图片懒加载示例</h1>
<div v-if="loading">加载中...</div>
<div v-else>
<div v-for="(image, index) in images" :key="index">
<img v-lazy="image.url" :alt="image.name" />
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
images: [], // 存放从后端获取的图片数据
loading: true // 控制加载状态
};
},
methods: {
// 从后端获取数据
async fetchImages() {
try {
const response = await axios.get('/api/images'); // 假设后端的 API 路径
this.images = response.data; // 假设返回的数据是一个图片对象数组
this.loading = false;
} catch (error) {
console.error('加载图片数据失败:', error);
this.loading = false;
}
}
},
created() {
// 组件创建时获取图片数据
this.fetchImages();
}
};
</script>
<style>
img {
width: 100%;
height: auto;
margin-bottom: 10px;
}
</style>
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)