Vue.js: Vue Router 路由

最后更新:2026-10-20

Vue Router 是 Vue 官方的路由管理器——让你的 SPA(单页应用)有多个"页面",每个 URL 对应一个组件。Vue Router 4 是 Vue 3 配套版本,完全支持 Composition API。

SPA 路由的核心是URL ↔ 组件的映射。掌握 Vue Router 4 是开发任何非 trivial Vue 应用的必备技能。

1. 你将学到


2. 一个 SPA 的"404 噩梦"

(1) 痛点:5 个页面,5 份重复代码

Alice 的后台有 5 个页面(Home/Products/Orders/Users/Settings):

4 个问题:

(2) Vue Router 4 解法:5 行路由 + 5 个组件

JS
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  { path: '/', component: () => import('@/views/HomePage.vue') },
  { path: '/products', component: () => import('@/views/ProductsPage.vue') },
  { path: '/orders', component: () => import('@/views/OrdersPage.vue') },
  { path: '/users', component: () => import('@/views/UsersPage.vue') },
  { path: '/settings', component: () => import('@/views/SettingsPage.vue') }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

5 行路由 + 1 个 router-view = 完整 SPA。URL 自动同步,浏览器前进/后退工作。

(3) 收益

使用 Vue Router 后:


3. 路由初始化

(1) 完整初始化代码

JS
// src/router/index.js
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'

// 1. 定义路由(懒加载)
const routes = [
  { path: '/', component: () => import('@/views/HomePage.vue') },
  { path: '/products', component: () => import('@/views/ProductsPage.vue') }
]

// 2. 创建 router 实例
const router = createRouter({
  // history 模式:URL 无 #(推荐)
  history: createWebHistory(),
  // hash 模式:URL 带 #(兼容老浏览器)
  // history: createWebHashHistory(),
  
  routes,
  
  // 滚动行为:路由切换时滚到顶部
  scrollBehavior(to, from, savedPosition) {
    return savedPosition || { top: 0 }
  }
})

export default router

(2) main.js 注册

(3) 2 大 history 模式对比

维度 createWebHistory createWebHashHistory
URL 形式 /products /#/products
SEO ✅ 友好 ❌ 不友好
服务器配置 需要(try_files) 不需要
浏览器兼容 IE10+ IE8+
推荐度 ⭐⭐⭐⭐⭐ ⭐⭐

4. 5 种路由配置

(1) 静态路由

JS
const routes = [
  { path: '/', component: () => import('@/views/HomePage.vue') },
  { path: '/about', component: () => import('@/views/AboutPage.vue') },
  { path: '/contact', component: () => import('@/views/ContactPage.vue') }
]

(2) 动态路由(参数)

JS
const routes = [
  // /products/123
  { 
    path: '/products/:id', 
    component: () => import('@/views/ProductDetailPage.vue') 
  },
  // /users/456/posts/789
  { 
    path: '/users/:userId/posts/:postId', 
    component: () => import('@/views/PostPage.vue') 
  },
  // 可选参数
  { 
    path: '/news/:category?', 
    component: () => import('@/views/NewsPage.vue') 
  }
]
VUE
<!-- ProductDetailPage.vue 接收参数 -->
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()
console.log(route.params.id)  // '123'
</script>

(3) 嵌套路由

JS
const routes = [
  {
    path: '/users',
    component: () => import('@/views/UsersPage.vue'),
    children: [
      {
        path: '',  // 默认子路由
        component: () => import('@/views/UsersListPage.vue')
      },
      {
        path: ':id',  // /users/123
        component: () => import('@/views/UserDetailPage.vue')
      }
    ]
  }
]

(4) 命名路由

JS
const routes = [
  { 
    path: '/products/:id', 
    name: 'product-detail',  // 命名路由
    component: () => import('@/views/ProductDetailPage.vue') 
  }
]
VUE
<!-- 通过 name 跳转,避免硬编码 URL -->
<router-link :to="{ name: 'product-detail', params: { id: 123 } }">
  Product 123
</router-link>

(5) 通配符 404

JS
const routes = [
  { path: '/', component: () => import('@/views/HomePage.vue') },
  // ... 其他路由
  {
    path: '/:pathMatch(.*)*',  // 匹配所有未定义的路由
    component: () => import('@/views/NotFoundPage.vue')
  }
]

▶ 示例:手写 Hash 路由器(CDN 模拟 SPA 路由)

▶ 展开运行示例(86 行)
▶ 试一试

输出:

TEXT
初始地址为 #/ 时 Home 链接高亮,内容区显示「🏠 Home / 这是首页」,底部显示「当前路由: / | 历史栈: 1 步」,「← 后退」按钮置灰。
点击 About 后内容变为「ℹ️ About / 关于我们」,历史栈变为 2 步,「← 后退」可用。
点击 User 123 显示「👤 User 123 / 用户资料页」;点击 Products 显示「📦 Products / 商品列表页…」。
点「← 后退」回到上一页,内容区与「当前路由」同步更新,历史栈只剩 1 步时后退按钮再次置灰。
⚠️ 此为教学演示 Hash 路由原理。生产项目用 vue-router 官方库(必须 Vite)。

(1) 📊 5 种导航方式速查

方式 代码 适用
声明式链接 <router-link to="/products"> 用户点击链接
字符串路径 router.push('/products') JS 跳转
命名路由 router.push({ name: 'products' }) 推荐(重命名不破坏)
动态参数 router.push({ name: 'user', params: { id: 123 } }) 详情页
Query 参数 router.push({ path: '/search', query: { q: 'vue' } }) 搜索/过滤

5. 5 种导航方式

(2) 编程式导航(router.push)

JS
import { useRouter } from 'vue-router'

const router = useRouter()

function goToProduct(id) {
  router.push(`/products/${id}`)  // 字符串
  // 或
  router.push({ name: 'product-detail', params: { id } })  // 对象
}

function goBack() {
  router.back()  // 后退
}

function goForward() {
  router.forward()  // 前进
}

function replaceCurrent() {
  router.replace('/login')  // 替换(不留历史)
}

(3) 5 种 push vs replace 区别

方式 行为 历史记录
router.push() 跳转到新页面 留下记录(可后退)
router.replace() 替换当前页面 不留记录(不可后退)
router.go(n) 前进/后退 n 步 走历史
router.back() 后退一步 走历史
router.forward() 前进一步 走历史

(4) 编程式 vs 声明式对比

场景 推荐
用户点击链接 router-link(声明式)
JS 触发跳转 router.push(编程式)
表单提交后跳转 router.push
登录后跳转 router.replace
404 自动回退 router.back

▶ 示例:hash 迷你路由(push / replace / back 的差别)

浏览器里跑不起真正的 vue-router(需要构建),这里用 location.hash + hashchange 手写一个迷你路由,专门演示编程式导航三种写法的历史记录差异。

▶ 试一试

输出:

TEXT
初始打开(地址栏没有 hash)时路径显示 /,当前页面「首页 Home」,hash 变化次数 0。
点 push('/products'):地址栏变 #/products,页面变「商品列表 Products」,次数 1。
点 replace('/search'):地址变 #/search,页面变「搜索结果 Search」,次数 2。
此时点 back()(或浏览器后退):直接回到初始的首页 /,#/products 那条记录已被 replace 覆盖——replace 不留历史。

6. 路由守卫(导航守卫)

(1) 3 种守卫类型

JS
// 1. 全局前置守卫(最常用)
router.beforeEach((to, from, next) => {
  const isLoggedIn = !!localStorage.getItem('token')
  
  if (to.meta.requiresAuth && !isLoggedIn) {
    next('/login')  // 跳登录
  } else {
    next()  // 放行
  }
})

// 2. 路由独享守卫
const routes = [
  {
    path: '/admin',
    component: () => import('@/views/AdminPage.vue'),
    beforeEnter: (to, from, next) => {
      if (isAdmin()) next()
      else next('/403')
    }
  }
]

// 3. 组件内守卫
// 组件内:beforeRouteEnter / beforeRouteUpdate / beforeRouteLeave

(2) 完整登录守卫示例

JS
// router/index.js
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  const isLoggedIn = !!token
  
  // 需要登录的页面
  if (to.meta.requiresAuth && !isLoggedIn) {
    return next({ 
      name: 'login', 
      query: { redirect: to.fullPath }  // 登录后跳回
    })
  }
  
  // 已登录访问登录页
  if (to.name === 'login' && isLoggedIn) {
    return next({ name: 'home' })
  }
  
  next()
})
JS
// 路由 meta 配置
const routes = [
  {
    path: '/dashboard',
    component: () => import('@/views/DashboardPage.vue'),
    meta: { requiresAuth: true }  // 需要登录
  }
]

7. 综合演练:电商后台登录守卫

▶ 示例:完整登录守卫(⚠️ 需 Vite 项目)

JS
// router/index.js
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  const isLoggedIn = !!token

  if (to.meta.requiresAuth && !isLoggedIn) {
    return next({ name: 'login', query: { redirect: to.fullPath } })
  }

  if (to.name === 'login' && isLoggedIn) {
    return next({ name: 'home' })
  }

  next()
})

// 路由 meta 配置
const routes = [
  {
    path: '/dashboard',
    component: () => import('@/views/DashboardPage.vue'),
    meta: { requiresAuth: true }  // 需要登录
  }
]
▶ 试一试

输出:

TEXT
未登录访问 /dashboard 时被重定向到 /login?redirect=/dashboard,地址栏保留原目标路径。
已登录再访问 /login 会直接跳到首页,不会停留在登录页。
访问公开页或已登录访问受保护页时守卫调用 next(),目标页面正常渲染。

(2) 📊 5 大常见错误速查

错误 现象 解决
router-view 缺失 页面不显示 添加 <router-view />
路由没懒加载 首屏慢 用 () => import() 动态导入
守卫死循环 跳不出 避免 next() 又触发 beforeEach
嵌套路由无 outlet 子页面不显示 父组件加 <router-view />
404 路由缺失 报错 加 path: '/:pathMatch(.*)*'

(3) 📊 5 大性能对比

模式 首屏 切换 适用
静态 import 慢 快 小项目
动态 import ⭐⭐⭐⭐⭐ 首次慢 推荐
路由分组懒加载 ⭐⭐⭐⭐⭐ 首次慢 大项目
prefetch ⭐⭐⭐⭐ 快 用户体验优先
SSR ⭐⭐⭐⭐⭐ 快 Nuxt 3

❓ 常见问题

Q createWebHistory 和 createWebHashHistory 选哪个?
A createWebHistory(URL 无 #,SEO 友好)需要服务器配置;createWebHashHistory(URL 带 #)兼容老浏览器。生产环境推荐 createWebHistory。
Q 动态路由怎么接收参数?
A 用 useRoute() 钩子:const route = useRoute(); route.params.id。
Q router.push 和 router.replace 区别?
A push 留历史记录(可后退),replace 替换当前(不留历史)。登录后用 replace(不能后退回登录页)。
Q 路由守卫能异步吗?
A 能。beforeEach(async (to, from, next) => { await checkAuth(); next() })。但要小心避免死循环。
Q 嵌套路由怎么实现?
A 父路由用 children: [] 配置子路由,父组件模板中加 <router-view /> 作为子路由出口。
Q Vue Router 4 和 Vue Router 3 区别?
A Vue Router 4 支持 Composition API(useRouter/useRoute),TypeScript 推断更强,导航守卫参数变了(to/from/next)。Vue 3 项目必须用 Vue Router 4。
Q 路由懒加载能提升多少性能?
A 首屏可减少 50-80% 加载时间(不加载未访问的页面)。大项目(10+ 页面)效果显著。
Q 路由守卫 meta 字段怎么用?
A 路由配置加 meta: { requiresAuth: true },守卫中用 to.meta.requiresAuth 访问。用于权限、标题、面包屑等。

📖 小节


📝 作业

  1. 基础题(难度⭐) 实现一个简单的多页 SPA:

    • 3 个页面:Home / About / Contact
    • 顶部导航 + 底部 router-view
    • 用 vue-router 配置路由
  2. 进阶题(难度⭐⭐) 实现电商商品路由:

    • /products 列表页
    • /products/:id 详情页(动态参数)
    • /products/:id/edit 编辑页
    • 404 处理
  3. 挑战题(难度⭐⭐⭐) 实现完整的电商后台路由系统:

    1. 10+ 页面(home/products/orders/users/settings/login/404 等)
    2. 嵌套路由(/admin/dashboard, /admin/products 等)
    3. 路由懒加载(首屏快)
    4. 登录守卫(未登录跳 /login,登录后跳回)
    5. 5 种导航方式全覆盖
    6. 编程式导航(点击按钮跳转)
    7. TypeScript 强类型 routes 配置
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏