目录
一、路由是什么?项目为什么必须用路由
二、路由完整安装与初始化(项目标准流程)
1. 安装命令
2. 目录规范(工程化统一标准)
3. 路由基础配置 router/index.js(最简可运行模板)
4. 在 main.js 挂载路由
5. App.vue 放置路由出口(页面渲染容器)
三、两大核心 API:useRouter /useRoute(setup 必备)
核心区分一句话
四、页面跳转两种方式(声明式 + 编程式)
2. 编程式导航:router.push/replace /back(按钮、接口回调跳转)
五、路由传参两种方案(实战高频)
方案 1:动态路由 params(详情页、编辑页,参数在路径中)
1)路由配置 router/index.js
2)跳转传参
3)组件接收参数两种写法
方案 2:query 查询参数(搜索、筛选、分页,参数在?后)
传参避坑重点
六、嵌套路由(后台管理系统必备布局)
1. 路由配置 children
2. 父布局 Dashboard.vue 必须写二级路由出口
七、路由懒加载(性能优化核心)
1. 作用
2. 标准写法
3. 分包命名(打包后 chunk 文件自定义名称,方便排查)
八、路由守卫(权限控制,项目核心安全逻辑)
1. 全局前置守卫 beforeEach(最常用,统一登录校验)
2. 路由独享守卫 beforeEnter(单个路由单独校验)
3. 组件内守卫(setup 中使用)
九、实战常见问题与解决方案
1. 重复点击导航控制台报错
2. history 模式部署后刷新 404
3. params 参数刷新丢失
4. 路由跳转后页面不回到顶部
十、全文核心总结
单页应用 SPA 核心依赖就是路由,负责页面无刷新跳转、权限控制、页面参数传递、布局嵌套。本文基于 Vue3 +<script setup>组合式 API,全部为项目实战可复制代码,覆盖日常开发 90% 场景,适合长期复习。
一、路由是什么?项目为什么必须用路由
- 单页面无刷新切换:不用整页刷新,切换页面体验流畅,减少网络请求
- 页面分层管理:不同页面对应独立路由地址,区分首页、详情、登录、后台等模块
- 携带页面参数:列表跳转详情、搜索传参、分页参数存储在地址栏
- 权限拦截控制:未登录禁止访问后台、区分普通用户 / 管理员页面
- 布局嵌套:侧边栏 + 顶部导航 + 子页面通用后台布局,靠嵌套路由实现
- 性能优化:路由懒加载拆分代码包,减小首屏加载体积
版本匹配硬性规则:Vue3 必须装
vue-router@4;Vue2 使用vue-router@3,版本混用直接报错。
二、路由完整安装与初始化(项目标准流程)
1. 安装命令
bash
运行
# 安装vue-router4,写入生产依赖dependencies npm install vue-router@42. 目录规范(工程化统一标准)
plaintext
src/ ├─ router/ │ └─ index.js # 路由总配置文件 ├─ views/ # 页面级组件(路由页面) │ ├─ Home.vue │ ├─ Login.vue │ ├─ User.vue │ └─ Dashboard/ # 嵌套路由页面 │ ├─ Profile.vue │ └─ Order.vue └─ main.js # 挂载路由到Vue实例3. 路由基础配置 router/index.js(最简可运行模板)
js
运行
import { createRouter, createWebHistory } from 'vue-router' // 路由数组:统一管理所有页面映射 const routes = [ { path: '/', redirect: '/home' // 访问根路径自动重定向首页 }, { path: '/home', name: 'Home', // 命名路由,方便params传参 component: () => import('../views/Home.vue'), // 路由懒加载 meta: { title: '首页', requiresAuth: true } // 自定义元信息 }, { path: '/login', name: 'Login', component: () => import('../views/Login.vue'), meta: { title: '登录页', requiresAuth: false } }, // 404兜底页面,放路由数组最后 { path: '/:pathMatch(.*)*', component: () => import('../views/404.vue'), meta: { title: '页面不存在' } } ] // 创建路由实例 const router = createRouter({ history: createWebHistory(), // history模式(无#),生产需后端配置 // createWebHashHistory() hash模式(带#),本地开发无需后端 routes, scrollBehavior() { // 每次切换页面自动滚动到顶部 return { top: 0, left: 0 } } }) export default router4. 在 main.js 挂载路由
js
运行
import { createApp } from 'vue' import App from './App.vue' import router from './router' // .use(router) 全局注册路由,所有组件可用路由API createApp(App).use(router).mount('#app')5. App.vue 放置路由出口(页面渲染容器)
vue
<template> <!-- 路由导航链接,替代a标签,无刷新跳转 --> <router-link to="/home">首页</router-link> <router-link to="/login">登录</router-link> <!-- 路由出口:匹配到的页面组件在这里渲染 --> <router-view /> </template>三、两大核心 API:useRouter /useRoute(setup 必备)
核心区分一句话
useRouter:操作路由(跳转、返回、替换页面,对应 this.$router)useRoute:读取路由信息(路径、参数、meta,只读,对应 this.$route)
vue
<script setup> import { useRouter, useRoute } from 'vue-router' // 操作工具 const router = useRouter() // 当前路由信息对象 const route = useRoute() console.log(route.path) // 当前路径 /home console.log(route.meta.title) // 页面标题 console.log(route.query) // ?id=123 问号参数 console.log(route.params) // /user/123 动态路径参数 </script>四、页面跳转两种方式(声明式 + 编程式)
1. 声明式导航:<router-link>(模板中静态跳转)
vue
<!-- 基础路径跳转 --> <router-link to="/home">首页</router-link> <!-- query传参 /user?id=100 --> <router-link to="/user?id=100">用户100</router-link> <router-link :to="{ path: '/user', query: { id: 100 } }">用户100</router-link> <!-- 命名路由 + params传参 /user/100 --> <router-link :to="{ name: 'User', params: { id: 100 } }">用户详情</router-link>2. 编程式导航:router.push/replace /back(按钮、接口回调跳转)
vue
<script setup> import { useRouter } from 'vue-router' const router = useRouter() // 1. push 追加历史记录,可返回上一页(最常用) const goHome = () => router.push('/home') // query传参 const goUserQuery = () => router.push({ path: '/user', query: { id: 100 } }) // params动态参数(必须搭配name,不能写path) const goUserParams = () => router.push({ name: 'User', params: { id: 100 } }) // 2. replace 替换当前历史,无法返回上一页(登录/支付页使用) const toLogin = () => router.replace('/login') // 3. 页面返回 const goBack = () => router.back() // 返回上一页 router.go(-2) // 返回前两页 </script>五、路由传参两种方案(实战高频)
方案 1:动态路由 params(详情页、编辑页,参数在路径中)
1)路由配置 router/index.js
js
运行
{ path: '/user/:id', // :id 动态占位符 name: 'User', component: () => import('../views/User.vue'), props: true // 自动把params参数转为组件props,简化取值 }2)跳转传参
js
运行
router.push({ name: 'User', params: { id: 666 } }) // 地址栏:/user/6663)组件接收参数两种写法
写法 1:route.params 读取
vue
<script setup> import { useRoute } from 'vue-router' const route = useRoute() const userId = route.params.id </script>写法 2:props 接收(推荐,解耦路由依赖)
vue
<script setup> const props = defineProps(['id']) console.log(props.id) </script>方案 2:query 查询参数(搜索、筛选、分页,参数在?后)
- 特点:参数显示在地址栏,刷新页面不丢失,适合筛选条件
js
运行
// 跳转 router.push({ path: '/list', query: { keyword: 'vue', page: 1 } }) // 地址栏 /list?keyword=vue&page=1 // 接收 const route = useRoute() const keyword = route.query.keyword const page = route.query.page传参避坑重点
params搭配path会失效,必须使用命名路由name- params 刷新页面丢失参数;query 刷新保留
- 详情页 id、唯一标识用 params;搜索筛选用 query
六、嵌套路由(后台管理系统必备布局)
适用场景:侧边栏布局、个人中心子菜单、仪表盘多子页面
1. 路由配置 children
js
运行
{ path: '/dashboard', name: 'Dashboard', component: () => import('../views/Dashboard/Dashboard.vue'), meta: { title: '管理后台', requiresAuth: true }, children: [ // 默认子路由,访问/dashboard自动展示profile { path: '', redirect: 'profile' }, { path: 'profile', name: 'Profile', component: () => import('../views/Dashboard/Profile.vue'), meta: { title: '个人资料' } }, { path: 'order', name: 'Order', component: () => import('../views/Dashboard/Order.vue'), meta: { title: '订单列表' } } ] }2. 父布局 Dashboard.vue 必须写二级路由出口
vue
<template> <div class="layout"> <!-- 侧边栏导航 --> <div class="sidebar"> <router-link to="/dashboard/profile">个人资料</router-link> <router-link to="/dashboard/order">订单</router-link> </div> <!-- 子页面渲染出口 --> <router-view /> </div> </template>七、路由懒加载(性能优化核心)
1. 作用
打包时把每个路由页面单独拆分成 js 文件,访问该页面才加载对应代码,大幅减少首屏资源体积,解决首页加载缓慢问题。
2. 标准写法
js
运行
// 懒加载(推荐) component: () => import('../views/Home.vue') // 不推荐:一次性全部导入,首屏加载所有页面 import Home from '../views/Home.vue' component: Home3. 分包命名(打包后 chunk 文件自定义名称,方便排查)
js
运行
component: () => import(/* webpackChunkName: "user" */ '../views/User.vue')八、路由守卫(权限控制,项目核心安全逻辑)
路由守卫监听页面跳转全过程,拦截未登录、无权限访问页面,分全局守卫、路由独享守卫、组件内守卫。
1. 全局前置守卫 beforeEach(最常用,统一登录校验)
写在 router/index.js 路由实例后
js
运行
router.beforeEach((to, from, next) => { // to:目标页面路由对象 // from:当前离开页面 // next:放行/跳转函数 const token = localStorage.getItem('token') // 模拟登录凭证 // 自动设置页面标题 document.title = to.meta.title || '后台管理系统' // 1. 需要登录的页面,无token强制跳登录 if (to.meta.requiresAuth) { if (!token) { next('/login') } else { next() // 放行 } } else { // 2. 已登录用户禁止重复进入登录页 if (token && to.path === '/login') { next('/home') } else { next() } } })2. 路由独享守卫 beforeEnter(单个路由单独校验)
js
运行
{ path: '/admin', component: () => import('../views/Admin.vue'), beforeEnter: (to, from, next) => { // 仅管理员可访问 const role = localStorage.getItem('role') if (role === 'admin') next() else next('/404') } }3. 组件内守卫(setup 中使用)
vue
<script setup> import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router' // 离开当前页面前触发(表单未保存弹窗提示) onBeforeRouteLeave((to, from, next) => { const isEdit = true // 模拟表单已修改 if (isEdit && confirm('页面未保存,确定离开?')) { next() } else { next(false) // 取消跳转 } }) // 当前路由更新(同页面切换不同params,如/user/1 /user/2) onBeforeRouteUpdate((to) => { // 重新请求详情接口 console.log('新id:', to.params.id) }) </script>九、实战常见问题与解决方案
1. 重复点击导航控制台报错
js
运行
// router/index.js 路由实例后添加 const originalPush = router.push router.push = function push(location) { return originalPush.call(this, location).catch(() => {}) }2. history 模式部署后刷新 404
后端配置 nginx,将所有请求指向 index.html;本地开发使用createWebHashHistory()无此问题。
3. params 参数刷新丢失
改用 query 传参,或进入页面时从接口根据 id 重新拉取数据。
4. 路由跳转后页面不回到顶部
配置 scrollBehavior(前文基础配置已写)。
十、全文核心总结
- 安装规范:Vue3 固定
npm install vue-router@4,路由属于生产依赖,不加-D - 目录规范:统一 router/index.js 配置,views 存放页面组件
- 两大钩子区分:useRouter 做跳转操作,useRoute 读取参数信息
- 跳转方式:模板用
<router-link>,逻辑代码用 push/replace/back - 传参场景:详情 id 用 params,搜索筛选用 query
- 性能优化:所有页面统一使用路由懒加载拆分打包文件
- 布局方案:后台侧边栏、子菜单使用嵌套路由 children
- 权限控制:全局 beforeEach 守卫统一校验 token,meta 标记是否需要登录
- 页面拦截:表单保存提示使用组件内 onBeforeRouteLeave 守卫