Vue Router实战指南:从基础配置到高级路由控制
优化前:卡得不行
上周上线一个新功能,用户反馈“点一下路由跳转要等好几秒”,我一开始还不信,直到自己在测试环境点了一下——好家伙,首页进去后点个“个人中心”,白屏 4 秒多,连 loading 都没来得及显示。这哪是 SPA,简直是 S(Slow)PA。
项目用的是 Vue 3 + Vue Router 4,页面不算多,但有些路由组件里塞了大量子组件、图表、甚至内嵌的富文本编辑器。最离谱的是,有个“数据看板”页面,一进就发起 5 个 API 请求,还同步加载了 ECharts 和一堆工具函数,整个 JS bundle 直接飙到 2.8MB。首屏加载慢就算了,路由切换也卡,因为每次都是全量加载组件,完全没有懒加载。
找到瓶颈了!
先别急着改代码,得先搞清楚到底卡在哪。我打开了 Chrome DevTools 的 Performance 面板,录了一次路由跳转:
- JS 执行时间占了 3.2s,主要是组件初始化和第三方库解析
- Network 里看到所有路由组件的 JS 都在首页就加载完了
- Memory 快照显示,即使离开某个页面,组件实例和事件监听器也没被清理干净
再用 Lighthouse 跑了个分,Performance 只有 38 分,主要扣分项就是“减少 JavaScript 执行时间”和“避免庞大的 DOM”。基本可以确定:问题出在路由组件的加载策略和资源体积上。
核心优化一:路由懒加载,必须上
其实 Vue Router 官方早就推荐用动态导入做懒加载,但我之前图省事,全写成同步引入了。这次咬牙全改掉。
优化前:
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import Profile from '@/views/Profile.vue'
import Dashboard from '@/views/Dashboard.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/profile', component: Profile },
{ path: '/dashboard', component: Dashboard }
]
优化后:
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{ path: '/', component: () => import('@/views/Home.vue') },
{ path: '/profile', component: () => import('@/views/Profile.vue') },
{ path: '/dashboard', component: () => import('@/views/Dashboard.vue') }
]
就这么简单一行改动,打包后主包体积从 2.8MB 降到 1.1MB。而且路由切换时,只有访问对应页面才加载 JS,首屏快了不少。亲测有效,但注意:这里我踩过坑——如果用 Webpack 的 magic comment 做 chunk 命名,记得加 /* webpackChunkName: "profile" */,不然生成的文件名是 0.js、1.js 这种,不利于缓存。
核心优化二:组件级懒加载 + 按需引入
光路由懒加载还不够,有些页面内部还有重型组件。比如 Dashboard 里有个地图模块,用的是高德地图 SDK,光它自己就 600KB。我把它也拆成异步组件。
<template>
<div>
<LazyMap v-if="showMap" />
</div>
</template>
<script setup>
import { defineAsyncComponent } from 'vue'
const LazyMap = defineAsyncComponent(() =>
import('@/components/HeavyMap.vue')
)
const showMap = ref(false)
// 等用户点击“显示地图”才触发加载
</script>
同时,把 ECharts 改成按需引入:
// 以前
import * as echarts from 'echarts'
// 现在
import { init } from 'echarts/core'
import { BarChart } from 'echarts/charts'
import { GridComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
init().use([BarChart, GridComponent, CanvasRenderer])
这一套组合拳打下来,Dashboard 页面的 JS 体积从 1.2MB 降到 300KB 左右。而且用户不点地图,就不加载地图组件,体验顺滑多了。
小优化:预加载 + 缓存策略
对于高频跳转的页面(比如从首页到个人中心),可以提前预加载。Vue Router 本身不支持,但我们可以监听路由变化,在空闲时 prefetch 下一个可能访问的路由。
// 在 main.js 或 router 文件中
router.beforeEach((to, from) => {
// 预加载高频页面
if (from.path === '/' && to.path === '/profile') {
// 如果还没加载过,提前触发 import
import('@/views/Profile.vue').catch(() => {})
}
})
另外,对已加载的路由组件,可以配合 keep-alive 缓存,避免重复渲染。但要注意:缓存太多会吃内存,所以只缓存关键页面。
<keep-alive include="Profile,Settings">
<router-view />
</keep-alive>
这里注意我踩过好几次坑:include 的值必须是组件的 name,不是路径名!而且动态组件名要用变量,不能写死字符串(除非你确定不会变)。
性能数据对比
改完后重新跑了一遍数据(本地开发环境,关闭缓存,3G 网络模拟):
- 首屏加载时间:从 5.2s 降到 1.1s
- 路由跳转(首页 → 个人中心):从 4.1s 降到 780ms
- 主包体积:2.8MB → 1.1MB
- Lighthouse Performance 分数:38 → 82
最关键的是,用户反馈“终于不卡了”。虽然 Dashboard 第一次进还是有点慢(毕竟要加载图表),但至少不会白屏好几秒,而且后续跳转飞快。
还有一些小问题
当然,优化不是一劳永逸。现在还有两个小毛病:
- 首次进入 Dashboard 时,图表加载仍有 1s 左右的空白,考虑加骨架屏
- 某些低端机上,keep-alive 缓存多了会卡顿,打算加个最大缓存数限制
但这些问题不影响主流程,优先级不高,先放着。毕竟,能用就行,别过度优化。
以上是我的优化经验,有更好的方案欢迎交流
这次 Vue Router 性能优化,核心就是三点:路由懒加载、组件按需加载、合理缓存。说起来简单,但真要落地,得一个个页面抠,还得测各种机型。折腾了两天,值了。
如果你也在搞 Vue 项目,建议早点做懒加载,别等上线了被用户骂才改。这个技巧的拓展用法还有很多,比如结合 Web Worker 处理路由数据预处理,后续会继续分享这类博客。
以上是我踩坑后的总结,希望对你有帮助。有更优的实现方式?欢迎评论区交流!

暂无评论