组件懒加载
一、路由级懒加载(框架原生支持)
-
Vue Router 动态导入
使用
import()
语法实现路由级代码分割,访问对应路由时加载独立分包。
javascript
const router = new VueRouter({
routes: [
{ path: '/about', component: () => import('./views/About.vue') } // 生成独立 chunk
]
});
React Router v6+ 方案
结合 React.lazy
和 Suspense
实现按需加载:
javascript
const Home = React.lazy(() => import('./components/Home'));
<Suspense fallback={<Loading />}>
<Route path="/home" element={<Home />} />
</Suspense>
二、组件级懒加载(细粒度优化)
-
动态导入语法
在组件使用前通过
import()
延迟加载,适用于弹窗等非首屏内容:
javascript
// Vue
const Dialog = () => import('./Dialog.vue');
// React
const Editor = React.lazy(() => import('./Editor'));
条件触发加载
结合用户交互(如点击按钮)触发组件加载:
java
function loadComponent() {
import('./ChartComponent').then(module => {
const Chart = module.default;
// 渲染组件
});
}
三、构建工具配置(底层支持)
-
Webpack 代码分割
- 通过
splitChunks
配置公共模块分包:
- 通过
css
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: { test: /node_modules/, name: 'vendors' }
}
}
}
- 使用
/* webpackChunkName: "chunk-name" */
自定义分包名称。
-
Vite 自动分包
动态导入自动生成独立 chunk,无需额外配置。
四、优化策略
-
预加载关键资源
对高优先级分包添加
webpackPreload
注释,提前加载:
go
import(/* webpackPreload: true */ './CriticalComponent');
-
缓存优化
- 分包命名包含哈希值(如
[contenthash]
),利用浏览器长效缓存。 - Webpack 5 配置
cache: { type: 'filesystem' }
加速二次构建。
- 分包命名包含哈希值(如
错误处理与降级
封装加载逻辑,捕获网络异常并提供重试机制:
javascript
const loadWithRetry = async (url, retries = 3) => {
try {
return await import(url);
} catch (err) {
if (retries > 0) return loadWithRetry(url, retries - 1);
throw err;
}
};
总结
前端实现懒加载需结合框架特性与构建工具:
- 路由/组件级动态导入 触发自动分包(Vue/React 原生支持);
- 构建配置 优化拆分策略(Webpack/Vite 定制化);
- 预加载+缓存 平衡性能与用户体验。
通过分层加载策略,可降低首屏资源体积 30%~50%34,显著提升交互响应速度。
图片的懒加载
一使用第三方库 vue-lazyload
适用场景 :需要快速集成和丰富功能(加载态、错误处理)
实现步骤:
-
安装依赖
npm install vue-lazyload
全局配置
javascript
// main.js
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload, {
preLoad: 1.3, // 预加载高度比例
error: require('@/assets/error.png'), // 错误占位图
loading: require('@/assets/loading.gif'), // 加载中占位图
attempt: 3, // 重试次数
observer: true, // 开启 IntersectionObserver
observerOptions: {
rootMargin: '0px 0px 200px 0px'
}
})
组件中使用
xml
<template>
<img v-lazy="imageUrl" :alt="description">
</template>
二使用原生 Intersection Observer API(推荐)
原理 :通过浏览器原生 API 监听图片是否进入可视区域,触发加载
优点 :无依赖、性能好、支持动态内容
实现步骤:
- 注册全局自定义指令
javascript
// main.js
Vue.directive('lazy', {
inserted: (el, binding) => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = new Image()
img.src = binding.value
img.onload = () => {
el.src = binding.value // 加载完成后替换src
observer.unobserve(el) // 停止观察
}
img.onerror = () => console.error('图片加载失败')
}
})
}, {
rootMargin: '0px 0px 200px 0px' // 提前200px加载
})
observer.observe(el)
}
})
组件中使用
xml
<template>
<img v-lazy="imageUrl" :alt="description">
</template>
<script>
export default {
data() {
return {
imageUrl: 'https://example.com/image.jpg',
description: '示例图片'
}
}
}
</script>