Vue3 路由完全指南:从基础配置到权限控制
Vue Router 是 Vue 生态的核心插件之一,用于实现单页应用(SPA)的路由管理。Vue3 对应的 Vue Router 4 版本,相比 Vue2 有不少 API 变化和功能升级。本文将从基础配置出发,逐步讲解路由导航、参数传递、嵌套路由和权限控制,帮你掌握 Vue3 路由的核心用法。
一、环境准备:安装与基本配置
1. 安装 Vue Router 4
# Vue3 项目中安装
npm install vue-router@42. 创建路由实例
在 src/router/index.ts 中创建路由实例,定义路由规则:
// src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
// 导入页面组件
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
import NotFound from '@/views/NotFound.vue'// 定义路由规则
const routes: RouteRecordRaw[] = [{path: '/', // 路径name: 'Home', // 路由名称(可选,用于命名路由)component: Home // 对应的页面组件},{path: '/about',name: 'About',component: About},{// 404 页面:匹配所有未定义的路径path: '/:pathMatch(.*)*',name: 'NotFound',component: NotFound}
]// 创建路由实例
const router = createRouter({// 路由模式:HTML5 History 模式(无 # 号)history: createWebHistory(),// 路由规则routes
})export default router3. 挂载路由到应用
在 src/main.ts 中导入路由实例,并通过 app.use() 挂载:
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 导入路由实例const app = createApp(App)
app.use(router) // 挂载路由
app.mount('#app')二、基础用法:路由导航与出口
1. 路由出口:<RouterView>
在根组件 App.vue 中使用 <RouterView> 作为路由匹配组件的渲染出口 —— 匹配的路由组件会在这里渲染。
<!-- src/App.vue -->
<template><div class="app"><!-- 导航区 --><nav><!-- 路由链接:<RouterLink> 替代 <a> 标签 --><RouterLink to="/">首页</RouterLink><RouterLink to="/about">关于</RouterLink></nav><!-- 路由出口:匹配的组件在这里渲染 --><RouterView /></div>
</template><script setup>
import { RouterLink, RouterView } from 'vue-router'
</script>2. 路由导航的两种方式
(1)声明式导航:<RouterLink>
to属性:指定跳转路径(支持字符串或对象)active-class:路由激活时的样式类(默认router-link-active)
<!-- 字符串写法 -->
<RouterLink to="/home" active-class="active">首页</RouterLink><!-- 对象写法(推荐,路径变化时无需修改) -->
<RouterLink :to="{ name: 'Home' }" active-class="active">首页</RouterLink>(2)编程式导航:useRouter
在组件逻辑中通过 useRouter 钩子获取路由实例,调用 push/replace 等方法实现跳转,适合需要在事件或异步操作后跳转的场景。
<template><button @click="goToAbout">跳转到关于页</button>
</template><script setup>
import { useRouter } from 'vue-router'
const router = useRouter()const goToAbout = () => {// 方式1:通过路径router.push('/about')// 方式2:通过路由名称(推荐)router.push({ name: 'About' })
}
</script>三、路由参数传递:Query 与 Params
在实际开发中,经常需要在路由跳转时传递参数(如商品 ID、用户信息),Vue Router 提供了两种核心传参方式:Query 和 Params。
1. Query 参数(查询参数)
- 特点:参数会拼接在 URL 后面,格式为
?key=value - 适用场景:可选参数、过滤条件、分页等(如搜索关键词、页码)
传递参数:
<!-- 声明式导航 -->
<RouterLink :to="{ path: '/search', query: { keyword: 'vue3', page: 1 }
}">搜索 Vue3</RouterLink><!-- 编程式导航 -->
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const goToSearch = () => {router.push({path: '/search',query: { keyword: 'vue3', page: 1 }})
}
</script>接收参数:通过 useRoute 钩子获取路由信息,从 route.query 中读取参数:
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
// 读取 Query 参数
console.log(route.query.keyword) // 'vue3'
console.log(route.query.page) // '1'(注意:Query 参数默认是字符串类型)
</script>2. Params 参数(动态路由参数)
- 特点:参数嵌入 URL 路径中,格式为
/path/:param - 适用场景:必需参数、资源标识符(如商品 ID、用户 ID)
步骤 1:配置动态路由在路由规则中通过 :param 定义动态参数:
// src/router/index.ts
const routes: RouteRecordRaw[] = [{path: '/user/:id', // 动态参数 idname: 'User',component: () => import('@/views/User.vue') // 懒加载组件}
]步骤 2:传递参数
<!-- 声明式导航 -->
<RouterLink :to="{ name: 'User', // 必须用 name 跳转,不能用 pathparams: { id: 123 }
}">用户 123</RouterLink><!-- 编程式导航 -->
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const goToUser = () => {router.push({name: 'User',params: { id: 123 }})
}
</script>步骤 3:接收参数通过 route.params 读取参数:
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
// 读取 Params 参数
console.log(route.params.id) // '123'(字符串类型)
</script>3. Query 与 Params 对比
| 对比维度 | Query 参数 | Params 参数 |
|---|---|---|
| URL 形式 | /search?keyword=vue3 | /user/123 |
| 路由配置 | 无需特殊配置 | 需在 path 中定义占位符 |
| 跳转方式 | 支持 path 或 name | 仅支持 name(path 会忽略) |
| 参数类型 | 均为字符串 | 均为字符串 |
| 刷新页面 | 参数保留 | 参数保留(需配置占位符) |
| 适用场景 | 可选参数、过滤条件 | 必需参数、资源 ID |
四、嵌套路由:实现多级页面结构
当页面存在多级导航(如 “首页 → 商品列表 → 商品详情”)时,需要使用嵌套路由(子路由)。
1. 配置嵌套路由
在父路由规则中通过 children 字段定义子路由:
// src/router/index.ts
const routes: RouteRecordRaw[] = [{path: '/product',name: 'Product',component: () => import('@/views/Product.vue'),// 子路由配置children: [{path: 'list', // 子路径(完整路径:/product/list)name: 'ProductList',component: () => import('@/views/ProductList.vue')},{path: 'detail/:id', // 子路由动态参数(完整路径:/product/detail/123)name: 'ProductDetail',component: () => import('@/views/ProductDetail.vue')}]}
]2. 预留子路由出口
在父组件(Product.vue)中添加 <RouterView>,作为子组件的渲染出口:
<!-- src/views/Product.vue -->
<template><div class="product"><!-- 父组件内容 --><h2>商品管理</h2><!-- 子路由导航 --><nav><RouterLink :to="{ name: 'ProductList' }">商品列表</RouterLink><RouterLink :to="{ name: 'ProductDetail', params: { id: 123 } }">商品详情</RouterLink></nav><!-- 子路由出口:子组件在这里渲染 --><RouterView /></div>
</template>五、路由懒加载:优化性能
路由懒加载(动态路由加载)通过 import() 语法,将不同路由的组件代码分割成独立的代码块,仅在访问该路由时才加载对应的代码,从而减小初始加载体积。
1. 基础用法
将路由规则中的 component 改为返回 import() 调用的函数:
// src/router/index.ts
const routes: RouteRecordRaw[] = [{path: '/about',name: 'About',// 懒加载组件:访问 /about 时才加载component: () => import('@/views/About.vue')},{path: '/user/:id',name: 'User',// 命名代码块(便于调试)component: () => import(/* webpackChunkName: "user" */ '@/views/User.vue')}
]2. 配合异步组件处理加载状态
若需要在组件加载过程中显示加载动画或处理错误,可结合 Vue 的 defineAsyncComponent 封装:
import { defineAsyncComponent } from 'vue'// 封装懒加载组件
const User = defineAsyncComponent({loader: () => import('@/views/User.vue'), // 加载函数loadingComponent: () => import('@/components/Loading.vue'), // 加载中显示errorComponent: () => import('@/components/Error.vue'), // 加载失败显示delay: 200, // 延迟 200ms 显示 loading(避免闪烁)timeout: 5000 // 5 秒后加载失败
})// 路由配置
const routes: RouteRecordRaw[] = [{ path: '/user/:id', name: 'User', component: User }
]六、路由守卫:实现权限控制
路由守卫用于在路由跳转前后执行自定义逻辑,最常见的场景是权限控制(如未登录用户禁止访问首页)。Vue Router 提供了三种类型的守卫:全局守卫、路由独享守卫、组件内守卫。
1. 全局前置守卫(最常用)
在 src/router/index.ts 中定义全局前置守卫,每次路由跳转前执行:
// src/router/index.ts
import router from './index'// 全局前置守卫
router.beforeEach((to, from, next) => {// to:即将进入的目标路由// from:当前离开的路由// next:控制导航的函数// 示例:未登录用户禁止访问 /user 路由const isLogin = localStorage.getItem('token') // 假设 token 存在表示已登录if (to.path.startsWith('/user') && !isLogin) {// 未登录,重定向到登录页next('/login')} else {// 已登录,允许导航next()}
})2. 组件内守卫
在组件内部定义守卫,仅对当前组件生效:
<script setup>
import { onBeforeRouteEnter, onBeforeRouteLeave } from 'vue-router'// 进入组件前执行
onBeforeRouteEnter((to, from, next) => {// 注意:此时组件实例尚未创建,无法访问 thisconsole.log('进入组件前')next()
})// 离开组件前执行
onBeforeRouteLeave((to, from, next) => {// 示例:未保存数据时提示用户const isSaved = confirm('数据未保存,确定离开吗?')if (isSaved) {next()} else {next(false) // 取消导航}
})
</script>七、总结
Vue Router 4 为 Vue3 提供了强大的路由管理能力,核心知识点包括:
- 基础配置:创建路由实例、挂载路由、路由出口
- 路由导航:声明式(
<RouterLink>)和编程式(useRouter) - 参数传递:Query(查询参数)和 Params(动态路由参数)
- 嵌套路由:通过
children配置子路由,预留子路由出口 - 性能优化:路由懒加载减少初始加载体积
- 权限控制:通过路由守卫实现登录验证、权限校验
