一、Vue Router 4 基础认知,和前代有啥不同?
p>想系统掌握 Vue Router 4,得先理清它在 Vue3 生态里的角色和学习逻辑,简单说,路由是单页应用(SPA)实现“多页面感”的核心工具,Vue Router 4 作为 Vue3 官方路由库,和 Vue3 组合式 API、响应式系统深度绑定,用法和 Vue Router 3(对应 Vue2)差异不小,下面通过“基础认知、核心功能、进阶能力、实战场景、避坑学习”五大模块,用问答形式拆解关键知识点,帮你把技术点串成可落地的技能。
问题1:Vue Router 4 是做什么的?和 Vue Router 3 核心差异在哪?Vue Router 4 是 Vue3 生态中负责管理页面跳转规则、组件与路径映射、导航逻辑的工具库,和 Vue Router 3 相比,核心差异体现在这几点:
- 初始化方式:Vue3 用
createApp
构建应用,Vue Router 4 改用createRouter
+createWebHistory
/createWebHashHistory
配置路由,告别 Vue2 时代的new Router()
。 - 组合式 API 支持:新增
useRouter
、useRoute
等组合式函数,在setup
语法糖中能更简洁地操作路由(比如获取参数、编程式导航)。 - 性能优化:支持 Tree-shaking,打包时自动剔除未使用的路由功能,减少项目体积。
- 路由匹配逻辑:动态路由、嵌套路由的配置细节更严谨(比如嵌套路由
children
需严格对应父组件的<router-view>
结构)。
问题2:项目里怎么安装 Vue Router 4?基本配置步骤是啥?
安装很简单,用包管理器执行命令:
npm install vue-router@4 # 或 yarn add vue-router@4
配置分三步(以 Vue3 + Vite 项目为例):
- 创建路由实例:在
src/router/index.js
中定义路由规则和模式:import { createRouter, createWebHistory } from 'vue-router' // 导入组件(懒加载用动态 import) import HomeView from '../views/HomeView.vue'
const router = createRouter({ history: createWebHistory(), // History 模式(URL 无 #,需后端配置);Hash 模式用 createWebHashHistory routes: [ { path: '/', name: 'home', component: HomeView }, { path: '/about', name: 'about', component: () => import('../views/AboutView.vue') // 懒加载:访问时再加载组件 } ] })
export default router
2. **注入 Vue 应用**:在 `main.js` 中把路由实例挂载到 Vue 应用上:
```js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router) // 注入路由功能
app.mount('#app')
- 渲染路由组件:在
App.vue
中用<router-view>
显示匹配组件,<router-link>
做导航:<template> <div class="app-nav"> <router-link to="/">首页</router-link> <router-link to="/about">lt;/router-link> </div> <router-view></router-view> <!-- 匹配的组件会渲染到这里 --> </template>
核心功能实操:动态路由、嵌套路由咋玩?
问题3:动态路由(带参数的路由)怎么配置和使用?
动态路由用于路径含变量的场景(比如用户 ID、文章 ID),配置时在 path
中加 :参数名
,示例:
routes: [ { path: '/user/:id', // :id 是动态参数 name: 'User', component: () => import('../views/UserView.vue') } ]
组件内获取参数分两种方式:
- 组合式 API:用
useRoute()
获取当前路由对象,通过route.params.id
拿到参数:import { useRoute, watch } from 'vue-router' export default { setup() { const route = useRoute() // 监听参数变化(因为动态路由复用组件时,生命周期不触发,需手动监听) watch(() => route.params.id, (newId) => { console.log('用户 ID 变化:', newId) // 这里可执行请求新用户数据等逻辑 }) } }
- 选项式 API:通过
this.$route.params.id
获取参数,同样需注意组件复用时的参数监听(用watch: { '$route.params.id'() {} }
)。
问题4:嵌套路由怎么设计?适合什么场景?
嵌套路由是“父路由包含子路由”的结构,典型场景是后台管理系统(/layout
页面包含侧边栏、顶栏,中间 <router-view>
显示子页面如 /layout/dashboard
)。
配置时用 children
数组:
routes: [ { path: '/layout', component: LayoutView, // 父组件,需包含 <router-view> 显示子组件 children: [ { path: 'dashboard', // 注意:path 不加 /,自动拼接为 /layout/dashboard name: 'Dashboard', component: DashboardView }, { path: 'settings', name: 'Settings', component: SettingsView } ] } ]
父组件 LayoutView
的模板需包含 <router-view>
:
<template> <div class="layout-container"> <aside>侧边导航栏</aside> <main> <router-view></router-view> <!-- 子路由组件渲染到这里 --> </main> </div> </template>
这种设计让“父布局逻辑”和“子页面内容”解耦,代码更模块化。
问题5:编程式导航(不用 <router-link>
跳转)怎么做?
场景比如“点击按钮跳转”“登录成功后跳转到首页”,用 useRouter()
拿到路由实例,调用 push
/replace
/go
等方法:
-
组合式 API 写法:
import { useRouter } from 'vue-router' export default { setup() { const router = useRouter() const goToAbout = () => { // 方式1:直接传路径 router.push('/about') // 方式2:传路由对象(name 对应路由配置的 name) router.push({ name: 'about' }) // replace:替换当前历史记录(返回时跳过当前页) router.replace('/about') // go(-1):返回上一页,类似 history.back() router.go(-1) } return { goToAbout } } }
-
选项式 API 写法:用
this.$router.push(...)
,用法和上面一致。
push
/replace
可传查询参数(如 router.push({ path: '/search', query: { keyword: 'vue' } })
),组件内通过 route.query.keyword
获取参数。
进阶能力:路由守卫、元信息、懒加载有啥用?
问题6:路由守卫是做什么的?全局守卫、组件内守卫怎么用?
路由守卫是“路由跳转前后的钩子函数”,用于权限验证、加载进度条、数据预加载等场景,分三类:
-
全局守卫:作用于所有路由跳转,在路由实例上配置:
router.beforeEach((to, from) => { ... })
:跳转前触发,返回值控制是否允许跳转(返回true
/undefined
允许;返回false
/路径字符串则中断并跳转)。
示例:权限验证(未登录则跳登录页):import { useUserStore } from '@/stores/user' // 假设用 Pinia 存用户状态
router.beforeEach((to) => { const userStore = useUserStore() if (to.meta.requiresAuth && !userStore.isLogin) { return '/login' // 无权限则跳登录页 } })
- `router.afterEach((to, from) => { ... })`:跳转完成后触发,适合“修改页面标题”“关闭加载动画”等操作。
-
路由独享守卫:在单个路由配置中写
beforeEnter
:{ path: '/admin', component: AdminView, beforeEnter: (to, from) => { if (!isAuthenticated()) return '/login' // 仅该路由触发此守卫 } }
-
组件内守卫:在组件的
setup
中用组合式 API 钩子(选项式 API 用beforeRouteUpdate
/beforeRouteLeave
):onBeforeRouteUpdate
:路由参数变化时触发(如/user/1
→/user/2
,组件复用场景)。onBeforeRouteLeave
:离开当前路由时触发(如“表单未保存时阻止跳转”)。
示例:离开页面时确认是否保存表单:
import { onBeforeRouteLeave } from 'vue-router' export default { setup() { onBeforeRouteLeave((to, from) => { if (form.dirty) { // 假设 form 有“是否修改”标记 return window.confirm('有未保存内容,确定离开?') } }) } }
问题7:路由元信息(meta)怎么配置和使用?
meta
是给路由加“额外信息”的字段,是否需要登录”“页面标题”,配置时在路由规则中加 meta
:
{ path: '/profile', component: ProfileView, meta: { requiresAuth: true, // 是否需要鉴权 '个人中心' // 页面标题 } }
使用场景:
- 全局守卫中统一处理页面标题:
router.beforeEach((to) => { if (to.meta.title) { document.title = to.meta.title } })
- 权限验证:结合
to.meta.requiresAuth
判断是否需要登录(如问题6的示例),让权限逻辑和路由配置解耦,维护更方便。
问题8:路由懒加载怎么实现?对性能有啥帮助?
路由懒加载是“组件按需加载”,减少首屏加载体积(初始只加载首页等核心资源,访问对应路由时再加载组件),Vue Router 4 用动态 import()
实现:
{ path: '/about', component: () => import('../views/AboutView.vue') // 访问 /about 时才加载组件 }
构建工具(如 Webpack、Vite)会把懒加载组件单独打包成 chunk
,访问对应路由时再请求该 chunk
,还能结合 Vue 的 <Suspense>
组件做加载状态:
<template> <Suspense> <template #default> <router-view></router-view> <!-- 渲染匹配的组件 --> </template> <template #fallback> <div>加载中...</div> <!-- 组件加载时显示的占位符 --> </template> </Suspense> </template>
这样既优化了首屏性能,又提升了用户体验(避免白屏)。
实战场景:Vue Router 4 怎么解决复杂需求?
问题9:多布局切换(比如前台/后台不同布局)怎么做?
场景:网站分“前台(首页、文章页)”和“后台(管理页面)”,布局完全不同,用动态组件 + 路由元信息实现:
-
定义布局组件:
LayoutFront.vue
(前台布局)、LayoutAdmin.vue
(后台布局)。 -
路由配置加
meta.layout
:routes: [ { path: '/', name: 'home', component: HomeView, meta: { layout: 'front' } // 前台布局 }, { path: '/admin', component: AdminView, meta: { layout: 'admin' }, // 后台布局 children: [...] // 后台子路由 } ]
-
在 App.vue 动态渲染布局:
<template> <component :is="layoutComponent"> <router-view></router-view> </component> </template>
这样不同路由会自动切换布局,代码结构更清晰。
问题10:路由错误处理(404 页面)怎么配置?
404 页面需匹配“所有未定义的路由”,因此要把通配符路由放在路由规则最后(路由匹配是“从上到下,一旦匹配就停止”),配置:
routes: [ // 其他路由... { path: '/:pathMatch(.*)*', // Vue Router 4 通配符写法,匹配所有路径 name: 'NotFound', component: () => import('../views/NotFoundView.vue') } ]
用户访问不存在的路径时,会跳转到 NotFoundView
,可在该组件内加“返回首页”按钮,提升体验:
<template> <div> <h1>404 - 页面走丢了</h1> <button @click="goHome">返回首页</button> </div> </template> <script setup> import { useRouter } from 'vue-router' const router = useRouter() const goHome = () => router.push('/') </script>
问题11:和 Pinia/Vuex 结合做权限控制,怎么设计?
以 Pinia 存储用户登录状态为例,在全局前置守卫中判断权限:
import { useUserStore } from '@/stores/user' router.beforeEach((to) => { const userStore = useUserStore() // 如果路由需要鉴权,且用户未登录 → 跳登录页并携带重定向参数 if (to.meta.requiresAuth && !userStore.isLogin) { return { name: 'login', query: { redirect: to.fullPath } } } })
登录组件中,登录成功后跳转到“重定向参数”对应的路径:
import { useRouter, useRoute } from 'vue-router' import { useUserStore } from '@/stores/user' export default { setup() { const router = useRouter() const route = useRoute() const userStore = useUserStore() const handleLogin = () => { userStore.login() // 执行登录逻辑(比如存 token) const redirect = route.query.redirect || '/' // 优先跳转到原目标页 router.push(redirect) } return { handleLogin } } }
这种设计实现了“权限控制 + 重定向”的完整流程,用户体验更流畅。
学习资源与避坑指南
问题12:学 Vue Router 4 看什么资料?怎么避常见坑?
-
学习资源:
- 官方文档:Vue Router 4 文档对概念、API、示例讲解极细,是权威参考。
- 实战项目:做一个“带权限的后台管理系统”,覆盖动态路由、嵌套路由、守卫、懒加载、多布局等场景,把知识点落地。
-
避坑指南:
-
路由模式选择:
- History 模式:URL 美观(无 #),但需后端配置(如 Nginx 把所有请求转发到
index.html
),否则刷新页面会 404。 - Hash 模式:URL 带 #(如
http://xxx/#/about
),无需后端配置,适合对 URL 美观度要求不高的项目。
- History 模式:URL 美观(无 #),但需后端配置(如 Nginx 把所有请求转发到
-
动态路由参数监听:
动态路由复用组件时(如/user/1
→/user/2
),组件生命周期不触发,需用watch
监听route.params
或用onBeforeRouteUpdate
守卫。 -
嵌套路由的 path 写法:
子路由的path
不要加 ,否则会被解析为根路径(如path: '/settings'
会变成 `/settings
-
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。