ThankNeko's Blog ThankNeko's Blog
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)

Hoshinozora

尽人事,听天命。
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)
  • Python笔记

  • C笔记

  • C++笔记

  • Arduino笔记

  • Web笔记

    • Html与标签介绍
    • Html常用标签
    • CSS基础
    • JavaScript基础
    • BOM和DOM
    • Bootstrap5
    • Vue介绍
    • Vue指令系统
    • Axios请求
    • Vue计算与监听属性
    • Vue组件
    • NodeJS环境
    • Vue项目
    • Vue路由
      • Vue路由
        • 介绍
        • 基本概念
        • 基本使用
        • 路由懒加载
        • 路由工作模式
        • 导航方式
        • 路由传参
        • 路由嵌套
        • 路由守卫
  • Dev
  • Web笔记
Hoshinozora
2025-12-09
目录

Vue路由

# Vue路由

# 介绍

Vue Router是Vue官方的路由管理库,用于构建单页面应用,使其能通过URL路径切换不同的组件,而无需刷新整个页面。

# 基本概念

概念 说明 示例
路由(Route) 路径规则:URL → 组件 { path: '/about', component: About }
路由器(Router) 管理所有路由的中心 createRouter({ routes })
路由出口(RouterView) 页面中显示匹配组件的位置 <router-view />

# 基本使用

  1. 安装插件
# 如果创建项目时没有安装,则需要手动安装
npm install vue-router
1
2
  1. 创建路由配置

src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
import AboutView from '@/views/AboutView.vue'

// 定义路由规则:路由路径 → 组件
const routes = [
  {
    // 名称(唯一标识符),可在路由跳转时使用名称进行跳转
    // 跳转时使用名称的好处是无需知道路由路径,并且如果修改路由路径,跳转代码无需改动
    name: 'home',
    path: '/',
    component: HomeView
  },
  {
    name: 'about',
    path: '/about',
    component: AboutView
  }
]

// 创建路由器实例
const router = createRouter({
  // HTML5 History 模式(无#)
  history: createWebHistory(),
  // 传入上面定义的路由规则
  routes
})

// 导出路由器实例,供main.js挂载
export default router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  1. 在main.js中挂载

src/main.js

// 引入路由
import router from './router'

// 在vue应用实例中挂载路由
app.use(router)
1
2
3
4
5
  1. 在App.vue中使用

src/App.vue

<template>
  <div>
    <!-- 导航菜单 -->
    <nav>
      <!-- 声明式导航:通过点击跳转到指定路径 -->
      <router-link to="/">首页</router-link>
    </nav>
    <!-- 路由出口:路由匹配的组件会在这里显示 -->
    <router-view />
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11

# 路由懒加载

按需加载组件,减小首屏体积。

// 组件通过匿名函数导入,只有在访问到路径时,才会加载对应组件进行渲染
const routes = [
  { path: '/', component: () => import('@/views/Home.vue') },
  { path: '/about', component: () => import('@/views/About.vue') }
]
1
2
3
4
5

# 路由工作模式

在Vue Router中,路由有两种工作模式。

# Hash模式

利用URL中的#部分来模拟路由变化,#后的内容不会发送给服务器,仅在前端处理。

优点是兼容性好,后端无需配置,所有请求都指向根路径 / 即可。缺点是URL不美观,且不符合RESTful风格规范。

例如:https://example.com/#/home

第一次访问时,如果没有使用懒加载,则会下载单页面文件和所有页面组件JS文件,跳转已下载的组件页面时,就无需请求服务器,只需要在前端处理。

建议定义路由规则时使用懒加载,这样在访问到页面时才会去下载对应页面的组件JS文件。

// 路由模式配置

// 在创建路由实例时指定
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
  // 使用Hash模式
  history: createWebHashHistory(),
  routes: [...]
})
1
2
3
4
5
6
7
8
9

# History模式(推荐)

URL看起来像真实的路径,且是无刷新跳转,通过 <router-link> 或 router.push() 跳转时,则会在路由变化由前端拦截,不向服务器发起新请求。

优点是URL 干净、美观、语义化,符合现代Web应用标准,缺点是需要后端fallback配置。

例如:https://example.com/home

和hash模式的区别只在URL形式和服务器配置,文件加载方式是一样的,所以也建议定义路由规则时使用懒加载。

// 路由模式配置

// 在创建路由实例时指定
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
  // 使用History模式
  history: createWebHistory(),
  routes: [...]
})
1
2
3
4
5
6
7
8
9
# nginx配置
server {
    listen 80;
    server_name example.com;
    index index.html;

    # Vue 项目构建后的 dist 目录
    root /path/to/your/dist;

    # 核心配置:所有前端路由fallback到index.html
    location / {
        # $uri:先尝试匹配真实文件
        # $uri/:再尝试匹配真实目录
        # /index.html:如果前面都找不到则返回index.html由前端路由接管
        try_files $uri $uri/ /index.html;
    }

    # 可选:静态资源缓存优化
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 导航方式

# 声明式导航

声明式导航就是在html中通过点击标签控制跳转。

会自动添加 .router-link-active 类(可用于高亮当前页)。

<!-- 前进跳转,同等于a标签跳转,但不会刷新页面 -->
<router-link to="/about">关于</router-link>

<!-- 除了指定路由路径,还可以指定路由名称 -->
<router-link :to="{ name: 'about' }">关于</router-link>

<!-- 替换当前页跳转 -->
<router-link replace to="/about">关于</router-link>
1
2
3
4
5
6
7
8

# 编程式导航

编程式导航就是通过JS代码控制跳转。

// 需要先获取路由实例
import { useRouter } from 'vue-router'
const router = useRouter()
1
2
3
# 前进跳转

router.push(location) 会添加历史记录,可通过回退返回上一页。

相当于点击 <router-link to="...">

// 通过路由路径
router.push('/about')

// 通过路由名称
router.push({name: 'about'})
1
2
3
4
5
# 替换当前页跳转

router.replace(location) 会替换当前历史记录,无法返回上一页。

相当于点击 <router-link replace to="...">

例如:登录成功后替换掉登录页,防止用户点后退回到登录页。

// 通过路由路径
router.replace('/home')
1
2
# 在历史记录中前进/后退

router.go(n) 参数n为正数是前进,为负数是后退。

// 前进一页,同等于router.forward()
router.go(1)
// 后退一页,同等于router.back()
router.go(-1)
// 后退两页
router.go(-2)
1
2
3
4
5
6

# 路由传参

vue-router还支持路由传参,提供以下 3 种主流传参方式:

# 动态路径参数(params)

参数是路径的一部分,适用于资源 ID、详情页标识等。

URL例如:/user/123

// 定义路由,先在路由规则路径中定义参数占位符
{
  // :id 是参数占位符
  // :id? 如果占位符后跟?号则表示是可选参数
  path: '/article/:id',
  name: 'ArticleDetail',
  component: ArticleDetail
}


// 跳转时传参,建议使用name+params,如果要使用路径则需要手动将参数拼接到路径上,所以不建议
// 会生成路径:/article/456
router.push({
  name: 'ArticleDetail',
  params: { id: 456 }
})


// 接收参数,在路由所指向的组件中接收参数
import { useRoute } from 'vue-router'
const route = useRoute()
// 始终会接收为字符串类型
console.log(route.params.id) // "456"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 查询参数(query)

附加在 ? 后,类似GET请求,适用于搜索、分页、筛选条件等。

URL例如: /search?q=vue&page=2

// 定义路由,无需特殊声明
{
  path: '/productlist',
  name: 'ProductList',
  component: ProductList
}


// 跳转时传参,可用name或path
// 会生成路径:/product-list?category=other&page=2&sort=price
router.push({
  name: 'ProductList',
  query: {
    category: 'other',
    page: 2,
    sort: 'price'
  }
})


// 接收参数,在路由所指向的组件中接收参数
import { useRoute } from 'vue-router'
const route = useRoute()
// 始终会接收为字符串类型
console.log(route.query.category) // "other"
console.log(route.query.page)     // "2"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 路由状态(state)

不显示在URL中,仅内存传递,适用于敏感数据、临时状态等。

URL不变。

// 跳转时传参,可用name或path
router.push({
  name: 'Checkout',
  state: {
    cartItems: [{ id: 1, name: 'Vue Book' }],
    total: 99.9
  }
})


// 接收参数,在路由所指向的组件中接收参数
import { useRoute } from 'vue-router'
const route = useRoute()
// 会保持参数传入时的数据类型
console.log(route.state.total)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 路由嵌套

# 介绍

路由嵌套用于构建具有父子页面结构的复杂界面。父路由组件中包含 <router-view />,子路由的组件会渲染在这个位置。

路由还支持多层级嵌套,即子路由中也可以使用children定义嵌套路由,不过需要每一层父组件都包含 <router-view /> 否则不会渲染子路由。

# 使用方式

1.定义嵌套路由

router/index.js

const routes = [
  {
    // 父组件路由
    path: '/user',
    component: UserLayout,
    // 使用children定义子组件的路由,子路由的path不需要写"/"开头
    children: [
      {
        // 空路径,即默认子路由,匹配路径/user
        path: '',
        name: 'UserProfile',
        component: UserProfile
      },
      {
        // 完整路径是父路由+子路由,匹配路径/user/settings
        path: 'settings',
        name: 'UserSettings',
        component: UserSettings
      },
      {
        // 动态子路由,会接收参数
        path: 'posts/:id',
        name: 'UserPostDetail',
        component: UserPostDetail
      }
    ]
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

2.父组件中包含 <router-view />

UserLayout.vue

<template>
  <div class="user-layout">
    <!-- 公共部分:导航菜单 -->
    <nav>
      <router-link to="/user">个人资料</router-link>
      <router-link to="/user/settings">设置</router-link>
    </nav>
    <!-- 子路由组件将在这里渲染 -->
    <router-view />
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11

# 路由守卫

路由守卫用于实现导航控制,能在路由跳转的各个阶段执行逻辑。

# 路由守卫的分类

类型 作用范围 典型用途
1. 全局守卫 所有路由跳转 登录验证 (未登录用户不能访问后台),全局Loading动画
2. 路由独享守卫 单个路由配置中 特定页面权限验证 (例如管理员后台权限验证)
3. 组件内守卫 单个组件内部 数据获取、离开确认 (表单未保存时提示用户)

执行顺序:beforeEach → 路由独享 beforeEnter → beforeResolve → 组件内 beforeRouteEnter → 导航确认 → 组件内(beforeRouteUpdate / beforeRouteLeave)

# 全局前置守卫

router.beforeEach(to, from) 在路由实例中添加全局前置守卫函数。

在每次导航开始前调用,且可中断导航。

可以用于权限控制、开启全局Loading动画等。

// router/index.js

// 路由定义
{
  path: '/admin',
  component: Admin,
  // 自定义元信息
  meta: { requiresAuth: true }
}

// 添加全局前置守卫
router.beforeEach((to, from) => {
  // 获取路由定义中的元数据,判断目标路由是否需要认证
  if (to.meta.requiresAuth && !isAuthenticated) {
    // 返回false表示取消导航
    // 返回undefined或true表示允许导航
    // 返回路径则表示中断当前导航,重定向到新路径
    return '/login'
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 全局解析守卫

router.beforeResolve(to, from) 在路由实例中添加全局解析守卫函数。

在所有组件内守卫和异步路由被解析后,导航确认前调用。

可用于确保数据加载完再显示页面。

router.beforeResolve(async (to, from) => {
  if (to.meta.requiresData) {
    try {
      // 等待数据加载
      await fetchData()
    } catch (error) {
      // 加载失败跳转错误页
      return '/error'
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11

# 全局后置守卫

router.afterEach(to, from) 在路由实例中添加全局后置守卫函数。

导航完成后调用,不能中断导航。

可以用于设置页面标题、埋点统计、关闭全局Loading动画等。

router.afterEach((to) => {
  // 设置页面标题
  document.title = to.meta.title || 'My App'
})
1
2
3
4

# 路由独享守卫

beforeEnter: (to, from) => {...} 在单个路由配置中定义,仅对该路由生效。

const routes = [
  {
    path: '/admin',
    component: Admin,
    beforeEnter: (to, from) => {
      // 只有这个路由会执行
      if (!isAdmin) {
        return '/forbidden'
      }
    }
  }
]
1
2
3
4
5
6
7
8
9
10
11
12

# 组件内守卫

beforeRouteEnter(to, from) 在组件中定义。

会在组件创建前调用。

import { onbeforeRouteEnter } from 'vue-router'

onbeforeRouteEnter((to, from) => {...})
1
2
3

beforeRouteUpdate(to, from) 在组件中定义。

当前路由改变但组件复用时调用。

import { onbeforeRouteUpdate } from 'vue-router'

onbeforeRouteUpdate((to, from) => {...})
1
2
3

beforeRouteLeave(to, from) 在组件中定义。

离开当前路由前调用,可取消导航。

import { onBeforeRouteLeave } from 'vue-router'

onBeforeRouteLeave((to, from) => {...})
1
2
3

# 示例

例如判断用户是否登录。

// router/index.js
router.beforeEach((to, from) => {
  // 排除登录和注册页面
  const publicPages = ['/login', '/register']
  const authRequired = !publicPages.includes(to.path)
  // 获取登录Token
  const isLoggedIn = localStorage.getItem('token')

  if (authRequired && !isLoggedIn) {
    return '/login'
  }
  if (!authRequired && isLoggedIn) {
    // 已登录用户访问登录页,重定向到首页
    return '/'
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#前端#Vue#路由
Vue项目

← Vue项目

最近更新
01
FastAPI实现用户管理
11-23
02
Tortoise ORM
11-23
03
FastAPI中间件与依赖
11-23
更多文章>
Theme by Vdoing | Copyright © 2022-2026 Hoshinozora | MIT License
湘ICP备2022022820号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式