图片懒加载技术
传统实现:getBoundingClientRect方法
图片懒加载是一种优化网页性能的重要技术,它通过延迟加载非可视区域内的图片来减少初始页面加载时间。传统实现方式主要依赖于getBoundingClientRect()
方法来检测元素是否在视口内。
javascript
// 判断元素是否在视口内的基本实现
const rect = element.getBoundingClientRect();
const isInViewport = rect.top < window.innerHeight && rect.bottom >= 0;
这种方法的核心原理是:
- 获取所有需要懒加载的图片元素
- 遍历这些图片,使用
getBoundingClientRect()
获取位置信息 - 判断图片是否出现在可视区域内
- 如果图片在可视区域内,则将
data-src
的值赋给src
属性
性能问题与优化 : 由于滚动事件会频繁触发,导致getBoundingClientRect()
被高频调用,这会引发**回流(reflow)**问题,严重影响页面性能。解决方案是添加节流函数来控制检测频率。
现代实现:Intersection Observer API
Intersection Observer API提供了更高效的懒加载实现方式,它避免了频繁计算元素位置带来的性能问题。
javascript
const io = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.origin;
io.unobserve(img); // 加载完成后移除观察
}
});
},
{
threshold: [0, 0.25, 0.5, 0.75, 1] // 设置多个阈值
}
);
// 观察所有需要懒加载的图片
const images = document.querySelectorAll("img[data-origin][lazyload]");
images.forEach((item) => {
io.observe(item);
});
优势分析:
- 不触发回流:由浏览器异步处理交叉检测,避免强制布局计算
- 配置灵活:可设置阈值、根元素等参数精确控制触发时机
- 代码简洁:无需手动监听滚动事件和计算元素位置
React组件缓存技术
实现原理与核心代码
在单页面应用(SPA)中,组件缓存是保持状态的重要技术。以下是一个基于React Router的组件缓存实现:
jsx
import { createContext, useContext } from "react";
import { useLocation, useOutlet } from "react-router";
// 缓存组件对象
const keepElements: Record<string, any> = {};
// 创建上下文
const KeepAliveContext = createContext({
keepPath: [] as string[],
keepElements,
dropByPath(path: string) {
keepElements[path] = null;
},
});
// 判断路径是否需要缓存
const isKeepPath = (keepPath: string[], path: string) => {
return keepPath.includes(path);
};
// 自定义Outlet钩子
export function useKeepOutlet() {
const location = useLocation();
const element = useOutlet();
const { keepPath, keepElements } = useContext(KeepAliveContext);
const isKeep = isKeepPath(keepPath, location.pathname);
if (isKeep) {
keepElements[location.pathname] = element;
}
return (
<>
{Object.entries(keepElements).map(([pathname, element]) => (
<div
key={pathname}
style={{ display: pathname === location.pathname ? 'block' : 'none' }}
>
{element}
</div>
))}
</>
);
}
// KeepAlive组件提供者
export function KeepAlive({ keepPath, children }) {
return (
<KeepAliveContext.Provider value={{ keepPath, keepElements }}>
{children}
</KeepAliveContext.Provider>
);
}
使用方式
jsx
// 在应用中使用
function App() {
return (
<KeepAlive keepPath={['/home', '/profile']}>
<Router>
{/* 路由配置 */}
</Router>
</KeepAlive>
);
}
// 在需要显示嵌套路由的组件中使用
function Home() {
return (
<div>
<h1>首页</h1>
{useKeepOutlet()}
</div>
);
}
技术对比与选择建议
图片懒加载方案选择
特性 | getBoundingClientRect | IntersectionObserver |
---|---|---|
性能影响 | 可能引起回流 | 无回流问题 |
代码复杂度 | 需要手动处理滚动事件 | 简单直观 |
浏览器兼容性 | 所有浏览器 | 现代浏览器 |
精确控制 | 需要手动计算 | 内置阈值配置 |
建议:在现代浏览器环境中优先使用IntersectionObserver API,对于需要支持老旧浏览器的项目,可使用getBoundingClientRect配合节流优化。
组件缓存适用场景
组件缓存技术特别适用于:
- 数据量较大的列表页/详情页场景
- 需要保持表单状态的页面
- 切换频繁的标签页内容
- 需要保持滚动位置的页面
总结
图片懒加载和组件缓存是前端性能优化的两种重要技术。懒加载通过延迟非关键资源加载提升页面加载速度,而组件缓存通过保持组件状态提升用户体验。