一、实现原理
-
核心思想:
- 只有当图片出现在视口中时,才加载图片。
- 利用占位图或占位背景优化用户体验。
-
实现技术:
- 监听滚动事件:监听页面滚动,通过计算图片与视口的位置关系,判断是否需要加载图片。
- Intersection Observer(推荐):现代浏览器提供的 API,用于检测目标元素是否进入视口,比滚动事件性能更好。
-
步骤:
- 设置图片的占位符(如灰色背景、默认图片)。
- 检测图片元素是否进入视口。
- 当图片进入视口时,将
src
属性替换为实际图片地址。
二、React 实现图片懒加载
1. 使用 Intersection Observer
实现
.
import React, { useRef, useState, useEffect } from 'react';
const LazyImage = ({ src, alt, placeholder, className }) => {
const [isLoaded, setIsLoaded] = useState(false);
const imgRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsLoaded(true);
observer.disconnect(); // 图片加载后停止观察
}
},
{ threshold: 0.1 } // 10% 进入视口时触发
);
if (imgRef.current) {
observer.observe(imgRef.current);
}
return () => {
if (observer && imgRef.current) {
observer.unobserve(imgRef.current);
}
};
}, []);
return (
<img
ref={imgRef}
src={isLoaded ? src : placeholder}
alt={alt}
className={className}
/>
);
};
export default LazyImage;
2. 第三方库
- react-lazyload:轻量级懒加载库,支持图片、组件等。
npm install react-lazyload
import React from 'react';
import LazyLoad from 'react-lazyload';
const LazyImage = ({ src, alt, height }) => (
<LazyLoad height={height} offset={100}>
<img src={src} alt={alt} />
</LazyLoad>
);
export default LazyImage;
三、Vue 实现图片懒加载
1. 使用 Intersection Observer
<template>
<img
:src="isLoaded ? src : placeholder"
:alt="alt"
ref="imageRef"
class="lazy-image"
/>
</template>
<script>
export default {
props: {
src: String,
placeholder: String,
alt: String,
},
data() {
return {
isLoaded: false,
};
},
mounted() {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
this.isLoaded = true;
observer.disconnect();
}
},
{ threshold: 0.1 }
);
observer.observe(this.$refs.imageRef);
},
};
</script>
2. 使用指令(全局注册)
懒加载在 Vue 中可通过自定义指令实现:
// directive-lazyload.js
export const lazyload = {
mounted(el, binding) {
const loadImage = () => {
const imageElement = el;
if (imageElement) {
imageElement.src = binding.value;
}
};
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
loadImage();
observer.disconnect();
}
});
observer.observe(el);
},
};
注册全局指令:
import { lazyload } from './directive-lazyload';
const app = createApp(App);
app.directive('lazyload', lazyload);
使用
<template>
<img v-lazyload="imageSrc" alt="Lazy loaded image" />
</template>
<script>
export default {
data() {
return {
imageSrc: 'https://example.com/image.jpg',
};
},
};
</script>
3. 第三方库
- vue-lazyload:
npm install vue-lazyload
import VueLazyload from 'vue-lazyload';
app.use(VueLazyload, {
loading: 'path/to/loading-image.png', // 占位图
error: 'path/to/error-image.png', // 错误图
});
<template>
<img v-lazy="imageSrc" alt="Lazy loaded image" />
</template>
四、性能优化与注意事项
- 减少主线程开销:优先使用
Intersection Observer
,避免滚动事件监听。 - 设置占位图:使用占位图片或颜色,避免加载空白区域影响体验。
- 图片格式优化:
- 使用 WebP 等高压缩比格式。
- 根据设备和网络情况选择适配图片(如
srcset
和picture
标签)。
- 懒加载阈值:通过设置
offset
或threshold
提前加载,提高滚动时的视觉连续性。 - 服务器优化:开启图片的
lazy
属性,结合懒加载策略。
通过上述方法,React 和 Vue 都可以灵活实现高性能的图片懒加载功能。