一、路由 / 组件懒加载
1. 路由懒加载(分包,首屏瘦身)
原理:路由组件单独打包,访问路由时才加载对应 js,不一次性加载全部页面
js
javascript
// router/index.js
// 原始(一次性加载所有页面,首屏大)
// import Home from '@/views/Home.vue'
// 懒加载写法
const Home = () => import('@/views/Home.vue')
const User = () => import(/* webpackChunkName: "user" */ '@/views/User.vue')
const routes = [
{ path: '/', component: Home },
{ path: '/user', component: User }
]
webpackChunkName 给分包命名,方便打包分析。
2. 组件局部懒加载(弹窗、tab、非首屏组件)
页面内不需要立刻渲染的组件(弹窗、下拉、折叠面板),用到再加载
vue
xml
<template>
<div>
<button @click="showModal = true">打开弹窗</button>
<Modal v-if="showModal" />
</div>
</template>
<script setup>
import { defineAsyncComponent } from 'vue'
const Modal = defineAsyncComponent(() => import('@/components/Modal.vue'))
let showModal = ref(false)
</script>
还能加加载、错误占位:
js
javascript
const Modal = defineAsyncComponent({
loader: () => import('@/components/Modal.vue'),
loadingComponent: Loading, // 加载中显示
errorComponent: ErrorTip, // 加载失败
delay: 200,
timeout: 5000
})
3. 图片懒加载
图片不在可视区不请求,滚动到再加载
- Vue2:
vue-lazyload - Vue3:
vue3-lazyload
vue
xml
<!-- 使用 -->
<img v-lazy="imgUrl" />
4. 第三方库懒加载(大图表、富文本、编辑器)
像 ECharts、Quill、Markdown 编辑器体积巨大,不要全局引入,使用时动态导入
js
dart
// 点击后才加载echarts
const openChart = async () => {
const { default: echarts } = await import('echarts')
const chart = echarts.init(dom.value)
}
二、打包体积优化(减少 js 文件大小,加载更快)
-
Tree Shaking 树摇 只打包代码用到的模块,删除未引入代码;使用 ESModule
import/export,禁用 require,webpack/vite 自动开启。 -
第三方库按需引入Element Plus、Ant Design Vue 不要全量导入,按需引入组件、样式
js
python// 按需导入,而非 import ElementPlus from 'element-plus' import { ElButton, ElInput } from 'element-plus' -
**分包策略 splitChunks(webpack)/build.rollupOptions(vite)**把 vue、vue-router、axios、UI 库等公共依赖单独抽离 vendor 包,浏览器缓存不用重复加载。
-
静态资源压缩
- 图片:webp/avif 格式、tinypng 压缩、雪碧图
- 字体:只打包用到的字符,减小字体文件
- 开启 gzip/brotli 压缩(nginx / 服务器配置)
-
移除 console、debugger生产环境清除打印日志,减少代码体积
-
替换重型库moment → dayjs;lodash 全量 → lodash-es 按需
三、渲染层面优化(减少 DOM 重绘重排,提升页面流畅度)
1. v-if 和 v-show 合理使用
v-if:销毁重建 DOM,适合切换频率低(弹窗、权限模块)v-show:display 控制,DOM 一直存在,适合频繁切换(tab、下拉)禁止同一元素同时写 v-if + v-for
2. v-for 必须加唯一 key,禁止用 index 做 key
index 作为 key 会引发 DOM 复用错乱、大量更新;用后端返回唯一 id。同时 v-for 外层套<template> 不生成多余 DOM 节点。
vue
xml
<template v-for="item in list" :key="item.id">
<div>{{ item.name }}</div>
</template>
3. 避免不必要的响应式劫持
大型列表、第三方纯数据不需要响应式:
shallowRef:浅层响应式,对象内部不劫持markRaw:完全脱离响应式系统(ECharts 实例、DOM、第三方类实例)
js
csharp
const chart = markRaw(echarts.init(dom))
4. 计算属性 computed 缓存数据
复杂遍历、筛选、格式化数据放在 computed,有缓存,依赖不变不重新计算;不要在 template 写复杂表达式。
vue
xml
<!-- 差写法:每次渲染都执行过滤 -->
<div>{{ list.filter(i=>i.age>18) }}</div>
<!-- 优写法:缓存 -->
<script setup>
const adultList = computed(() => list.value.filter(i=>i.age>18))
</script>
<div>{{ adultList }}</div>
5. 长列表虚拟滚动(百万级列表必用)
一次性渲染上万条 DOM 会卡顿,只渲染可视区域数据:vue2:vue-virtual-scrollervue3:vue3-virtual-scroller /element-plus-virtual-table
6. 减少全局频繁更新
- 大型表单拆分小组件,局部更新不整页刷新
- 频繁滚动、resize 事件使用防抖节流
js
javascript
// 节流,滚动每200ms执行一次
const handleScroll = throttle(()=>{}, 200)
7. 页面缓存 keep-alive
跳转回来不用重新请求接口、重新渲染页面,搭配路由缓存
vue
ini
<router-view v-slot="{ Component }">
<keep-alive include="Home,User">
<component :is="Component" />
</keep-alive>
</router-view>
include 指定需要缓存的组件名,exclude 排除,减少无意义重建。
四、响应式与数据更新优化
- 批量更新数据:Vue 自动异步批处理,连续赋值只会更新一次
- 大数据数组替换:不要循环 push,直接赋值
list.value = newArr - watch 合理使用:深度监听 deep 消耗性能,尽量用 computed 替代;不需要监听及时销毁
js
javascript
// 避免深度监听大对象
watch(obj, ()=>{}, { deep: true })
五、网络 & 接口优化
- 接口缓存:
localStorage/sessionStorage/pinia 缓存不常变动接口数据 - 请求节流:搜索输入框防抖,避免频繁发请求
- 接口分页,不一次性拉取全量数据
- CDN 加速静态资源(js、图片、字体)
- 接口合并,减少 http 请求次数
六、内存优化(防止页面越用越卡)
- 销毁组件清除定时器、监听、事件、第三方实例
js
scss
onUnmounted(()=>{
clearInterval(timer)
chart.dispose() // 销毁图表实例
window.removeEventListener('scroll', fn)
})
- 避免全局变量大量堆积,及时清空无用大数组
- 防止闭包内存泄漏
七、Vite/Webpack 工程化额外优化
- 生产环境关闭 sourceMap,减少打包产物
- 预构建依赖(vite 自动处理)
- 多环境区分,开发环境完整报错,生产极致压缩
- 图片资源内联小图标(小于 4kb 转 base64,减少请求)
八、CSS 优化辅助页面性能
- scoped 样式,避免全局样式污染、样式匹配耗时
- 少用复杂选择器、* 通配符
- 动画使用 transform/opacity(GPU 加速,不重排),少用 top/left
快速总结优先级
- 路由 + 组件懒加载(首屏最大优化点)
- 打包分包、按需引入第三方库(减小包体积)
- 长列表虚拟滚动、v-for 正确 key、computed 缓存(渲染卡顿)
- keep-alive 页面缓存、图片懒加载
- 防抖节流、销毁清除定时器 / 第三方实例(内存泄漏)
- gzip 压缩、接口缓存、TreeShaking