性能优化
本文档介绍前端性能优化的最佳实践。
代码优化
组件懒加载
typescript
// 路由懒加载
const routes = [
{
path: '/user',
component: () => import('@/views/user/index.vue')
}
];
// 组件懒加载
const UserList = defineAsyncComponent(() =>
import('@/components/UserList.vue')
);虚拟列表
对于大量数据的列表,使用虚拟滚动:
vue
<script setup lang="ts">
import { VirtualList } from '@vben/common-ui';
const data = ref(Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `Item ${i}`
})));
</script>
<template>
<VirtualList :data="data" :item-height="50">
<template #default="{ item }">
<div>{{ item.name }}</div>
</template>
</VirtualList>
</template>防抖和节流
typescript
import { debounce, throttle } from 'lodash-es';
// 防抖:延迟执行
const handleSearch = debounce((value: string) => {
console.log('搜索:', value);
}, 300);
// 节流:限制执行频率
const handleScroll = throttle(() => {
console.log('滚动');
}, 100);资源优化
图片优化
vue
<template>
<!-- 懒加载 -->
<img v-lazy="imageUrl" alt="image" />
<!-- WebP 格式 -->
<picture>
<source srcset="image.webp" type="image/webp" />
<img src="image.jpg" alt="image" />
</picture>
<!-- 响应式图片 -->
<img
srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
sizes="(max-width: 600px) 480px, (max-width: 900px) 800px, 1200px"
src="medium.jpg"
alt="image"
/>
</template>代码分割
typescript
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'ui-vendor': ['ant-design-vue'],
'utils': ['lodash-es', 'dayjs']
}
}
}
}
});渲染优化
v-show vs v-if
vue
<template>
<!-- 频繁切换使用 v-show -->
<div v-show="isVisible">内容</div>
<!-- 条件很少改变使用 v-if -->
<div v-if="isAdmin">管理员内容</div>
</template>计算属性缓存
vue
<script setup lang="ts">
// 使用计算属性,自动缓存
const filteredList = computed(() => {
return list.value.filter(item => item.status === 'active');
});
// 避免在模板中使用方法
// ❌ 不推荐
function getFilteredList() {
return list.value.filter(item => item.status === 'active');
}
</script>key 的使用
vue
<template>
<!-- 使用唯一 key -->
<div v-for="item in list" :key="item.id">
{{ item.name }}
</div>
<!-- 避免使用 index 作为 key -->
<!-- ❌ 不推荐 -->
<div v-for="(item, index) in list" :key="index">
{{ item.name }}
</div>
</template>网络优化
请求合并
typescript
// 使用 Promise.all 并发请求
async function fetchData() {
const [users, roles, depts] = await Promise.all([
getUserListApi(),
getRoleListApi(),
getDeptListApi()
]);
}请求缓存
typescript
// 使用缓存避免重复请求
const cache = new Map();
async function getUserInfo(userId: string) {
if (cache.has(userId)) {
return cache.get(userId);
}
const result = await getUserInfoApi(userId);
cache.set(userId, result);
return result;
}请求取消
typescript
import axios from 'axios';
const controller = new AbortController();
// 发起请求
axios.get('/api/data', {
signal: controller.signal
});
// 取消请求
controller.abort();构建优化
生产环境配置
typescript
// vite.config.ts
export default defineConfig({
build: {
// 压缩
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
// 分块
chunkSizeWarningLimit: 1000,
// 资源内联
assetsInlineLimit: 4096
}
});Tree Shaking
typescript
// 使用 ES6 模块导入
import { debounce } from 'lodash-es';
// 避免导入整个库
// ❌ 不推荐
import _ from 'lodash';监控和分析
性能监控
typescript
// 使用 Performance API
const start = performance.now();
// 执行操作
const end = performance.now();
console.log(`耗时: ${end - start}ms`);打包分析
bash
# 分析打包体积
pnpm build:analyze最佳实践
- 按需加载:路由和组件懒加载
- 代码分割:合理拆分代码块
- 资源优化:压缩图片、使用 WebP
- 缓存策略:合理使用浏览器缓存
- 减少重绘:避免频繁操作 DOM
- 虚拟滚动:大列表使用虚拟滚动
- 防抖节流:优化高频事件
- 预加载:关键资源预加载