解锁 Vue3 路由:原理、定义与实现全解析

Vue3 路由原理、定义与实现全解析

引言

在现代 Web 开发中,单页应用(SPA)已成为主流架构之一,而路由则是 SPA 实现页面切换与状态管理的核心机制。 对于 Vue3 开发者而言,Vue Router 作为官方配套的路由解决方案,不仅能无缝衔接 Vue3 的组合式 API,还能提供灵活的导航控制、路由守卫等功能,是构建复杂应用的必备工具。 本文将从路由原理入手,逐步讲解 Vue3 路由的定义方式与实际实现,帮助开发者从 “会用” 到 “懂原理”,高效解决路由开发中的常见问题。

Vue3 路由基础概念

什么是路由

路由的本质是 “URL 与资源的映射关系”。在传统多页应用中,URL 变化会触发页面刷新,服务器会返回对应页面的 HTML 资源; 而在 Vue3 单页应用中,路由通过 “无刷新” 的方式实现 URL 变化与组件渲染的关联 —— 即 URL 改变时,页面不重新加载,仅切换当前渲染的 Vue 组件,从而提升用户体验。

Vue Router 简介

Vue Router 是 Vue 官方推出的路由管理库,专门用于 Vue3 项目的路由控制,其核心功能包括:

  • 建立 URL 与 Vue 组件的映射关系;
  • 支持 “无刷新” 页面跳转(导航);
  • 提供动态路由、嵌套路由、路由懒加载等高级特性;
  • 通过 “导航守卫” 控制路由跳转的权限(如登录校验);
  • 支持 Hash、History 两种路由模式,适配不同部署场景。

Vue3 路由原理剖析

Vue Router 的核心原理是 “监听 URL 变化,匹配对应的路由规则,渲染目标组件”,其关键机制包括路由模式与导航守卫。

路由模式

Vue Router 支持三种路由模式,不同模式的核心区别在于 “如何监听 URL 变化” 与 “URL 的表现形式”,其中 Hash 和 History 模式最为常用。

Hash 模式

  • 原理:基于浏览器的 location.hash 属性实现。location.hash 指向 URL 中 # 后面的部分(如 https://xxx.com/#/home 中的 /home), 该部分的变化不会触发浏览器向服务器发送请求;Vue Router 通过监听 window 的 hashchange 事件,感知 hash 值的变化,进行匹配对应的路由规则。
  • URL 特点:包含 # 符号,如 https://my-blog.com/#/article/123
  • 优缺点
    • 优点:兼容性好,无需服务器端配置。
    • 缺点:URL 中包含 # 符号,不美观;hashchange 事件触发时,会导致浏览器滚动到顶部,影响用户体验。

History 模式

  • 原理:基于 HTML5 History API 实现。History API 提供了 pushStatereplaceState 方法, 这两个方法可以在不触发页面刷新的前提下,修改浏览器的历史记录与 URL;Vue Router 通过调用这两个方法改变 URL,并监听 window 的 popstate 事件(用户点击浏览器前进 / 后退按钮时触发),从而感知 URL 变化。
  • URL 特点:不包含 # 符号,如 https://my-blog.com/article/123
  • 优缺点
    • 优点:URL 美观,符合 RESTful 风格;不会触发页面刷新,用户体验好。
    • 缺点:兼容性差(仅支持 IE10+ 及现代浏览器,需要服务器端配置支持,否则刷新页面时,服务器会因找不到对应 URL 而返回 404(如 Apache 需开启 mod_rewrite 模块)。
  • 后端配置要求
    • Apache:需开启 mod_rewrite 模块,配置 RewriteEngine OnRewriteBase /
    • Nginx:需配置 location / { try_files $uri $uri/ /index.html; }
    1
    2
    3
    4
    5
    
    location / {
      root   /path/to/your/vue/app;
      index  index.html;
      try_files $uri $uri/ /index.html; # 关键配置:将所有请求转发到 index.html
    }
    
    • Node.js:可使用 connect-history-api-fallback 中间件。

Memory 模式

  • 原理:不依赖浏览器 URL,而是将路由状态存储在内存中(如,一个数组),仅在应用内部维护路由变化。
  • 适用场景:非浏览器环境,(如 Electron 桌面应用、Vue3 小程序),或不需要 URL 与路由关联的场景。
  • 特点:URL 不会随路由变化,刷新页面后路由状态会丢失。

导航守卫机制

导航守卫是 Vue Router 提供的 “路由跳转钩子”,用于在路由跳转的不同阶段执行自定义逻辑(如权限校验、页面埋点),其本质是 “拦截路由跳转,根据条件决定是否允许跳转”。 根据作用范围,导航守卫分为三类:

全局守卫

作用于所有路由,需在路由实例创建时配置,常用守卫包括:

  • beforeEach:路由跳转前触发(全局前置守卫),可用于登录校验;
  • afterEach:路由跳转后触发(全局后置守卫),可用于页面标题修改、埋点统计;

示例代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
  history: createWebHistory(),
  routes: [...], // 路由规则
});

// 全局前置守卫:登录校验
router.beforeEach((to, from, next) => {
  // to:目标路由;from:当前路由;next:继续跳转的函数
  const isLogin = localStorage.getItem('token'); // 假设token存储登录状态
  // 若未登录且目标路由需要登录,则跳转至登录页
  if (!isLogin && to.meta.requiresAuth) {
    next('/login');
  } else {
    next(); // 允许跳转
  }
});

// 全局后置守卫:修改页面标题
router.afterEach((to) => {
  document.title = to.meta.title || 'Vue3 App'; // 从路由元信息中获取标题
});

路由独享守卫

仅作用于指定路由,在路由规则中配置,常用 beforeEnter (路由进入前触发)。

示例代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const routes = [
  {
    path: '/article/:id', // 动态路由(:id 为参数)
    component: () => import('@/views/Article.vue'), // 懒加载组件
    meta: { title: '文章详情' },
    // 路由独享守卫:校验文章 ID 格式
    beforeEnter: (to, from, next) => {
      const articleId = to.params.id;
      // 若 ID 不是数字,则跳转至 404 页面
      if (!/^\d+$/.test(articleId)) {
        next('/404');
      } else {
        next();
      }
    }
  }
];

组件内守卫

作用于当前组件,在组件内部通过组合式 API 定义。常用守卫包括:

  • onBeforeRouteEnter:进入组件前触发(此时组件实例未创建,无法访问 this
  • onBeforeRouteUpdate:组件复用但路由参数变化时触发(如从 /article/1 跳转至 /article/2);
  • onBeforeRouteLeave:离开组件前触发(可用于提示 未保存的内容是否丢弃

示例代码(组合式 API):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
  <div>文章详情{{ articleId }}</div>
</template>

<script setup>
import { onBeforeRouteEnter, onBeforeRouteLeave, useRoute } from 'vue-router';
const route = useRoute();
const articleId = route.params.id; // 获取路由参数

// 进入组件前触发
onBeforeRouteEnter((to, from, next) => {
  // 可通过next(vm => { ... })访问组件实例vm
  next(vm => {
    console.log('进入组件,文章ID:', vm.articleId);
  });
});

// 离开组件前触发
onBeforeRouteLeave((to, from, next) => {
  const confirmLeave = window.confirm('内容未保存,是否离开?');
  confirmLeave ? next() : next(false); // 确认则离开,否则取消跳转
});
</script>

Vue3 路由的定义与配置

Vue3 路由的配置需遵循 “安装依赖 → 创建路由实例 → 定义路由规则 → 注入 Vue 应用” 的流程,以下是详细步骤。

安装 Vue Router

首先在 Vue3 项目中安装 Vue Router (需使用 4.x 版本,适配 Vue3),命令如下:

  • 使用 npm:
    1
    
    npm install vue-router@4 --save
    
  • 使用 yarn:
    1
    
    yarn add vue-router@4
    

创建路由实例

在项目中新建路由配置文件(通常为 src/router/index.js),通过 createRoutercreateWebHistory (或 createWebHashHistory) 创建路由实例:

示例代码:

 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
import { createRouter, createWebHistory } from 'vue-router';
// 引入组件(也可使用懒加载,见4.5节)
import Home from '@/views/Home.vue';
import Login from '@/views/Login.vue';
import Article from '@/views/Article.vue';
import NotFound from '@/views/NotFound.vue';

// 1. 定义路由规则
const routes = [
  { path: '/', redirect: '/home' }, // 重定向:默认跳转至/home
  { 
    path: '/home', 
    component: Home, 
    meta: { title: '首页', requiresAuth: false } // meta:路由元信息(自定义)
  },
  { path: '/login', component: Login, meta: { title: '登录' } },
  { path: '/article/:id', component: Article, meta: { title: '文章详情' } },
  { path: '/:pathMatch(.*)*', component: NotFound, meta: { title: '404' } } // 404路由
];

// 2. 创建路由实例
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL), // History模式(Vue3 Vite项目需加BASE_URL)
  // history: createWebHashHistory(), // 若使用Hash模式,替换上方代码
  routes // 传入路由规则
});

// 3. 导出路由实例(供main.js注入)
export default router;

注入 Vue 应用

在 Vue3 入口文件 (src/main.js) 中,通过 app.use(router) 将路由实例注入 Vue 应用,确保路由功能全局可用:

示例代码:

1
2
3
4
5
6
7
8
import { createApp } from 'vue';
import App from './App.vue';
import router from './router'; // 引入路由实例
import './style.css';

const app = createApp(App);
app.use(router); // 注入路由
app.mount('#app');

定义路由规则

路由规则是 routes 数组中的每一项,核心属性包括:

  • path:URL 路径(如 /home/article/:id
  • component:路径对应的 Vue 组件
  • meta:路由元信息(自定义属性,如 titlerequiresAuth
  • redirect:重定向(如 { path: '/', redirect: '/home' }
  • children:嵌套路由规则(见 嵌套路由

动态路由定义

当 URL 路径中包括 “可变参数” 时(如文章 ID、用户 ID),需使用动态路由,格式为 path: '/xxx/:参数名,参数可通过 useRoute().params 获取。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const routes = [
  {
    path: '/user/:username', // :username为动态参数
    component: () => import('@/views/User.vue'),
    meta: { title: '用户主页' }
  }
];

// 在User组件中获取参数(组合式API)
<script setup>
import { useRoute } from 'vue-router';
const route = useRoute();
console.log('用户名:', route.params.username); // 如URL为/user/zhangsan,则输出zhangsan
</script>

嵌套路由

当组件需要包含 “子组件” (如 “首页” 包含 “推荐”、“热门” 等子模块)时,需要使用嵌套路由,核心是通过 children 属性定义子路由,并在父组件中使用 <router-view> 渲染子组件。

示例步骤:

  1. 定义嵌套路由规则:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const routes = [
  {
    path: '/home',
    component: Home, // 父组件
    children: [
      { path: '', redirect: 'recommend' }, // 子路由默认重定向
      { path: 'recommend', component: HomeRecommend, meta: { title: '首页-推荐' } }, // 子路由1
      { path: 'hot', component: HomeHot, meta: { title: '首页-热门' } } // 子路由2
    ]
  }
];
  1. 在父组件(Home.vue)中添加 <router-view> (子组件渲染容器)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<template>
  <div class="home">
    <h1>首页</h1>
    <!-- 子路由导航 -->
    <nav>
      <router-link to="/home/recommend">推荐</router-link>
      <router-link to="/home/hot">热门</router-link>
    </nav>
    <!-- 子组件渲染位置 -->
    <router-view></router-view>
  </div>
</template>

Vue3 路由的实现与应用

定义好路由规则后,需通过 “路由导航” 实现页面切换,并结合动态路由、懒加载等特性优化应用体验。

路由跳转(导航)

Vue Router 提供两种导航方式:router-link 组件(声明式)和编程式导航(JS 代码)。

router-link 是 Vue Router 提供的专用组件,替代传统的 <a> 标签,避免页面刷新。核心属性包括:

  • to: 目标路由(可传字符串或对象,如 to="/home"to="{ path: '/article', query: { id: 1 } }"
  • replace:若添加该属性,跳转时会替换当前历史记录(而非新增),点击后退按钮不会返回当前页
  • active-class:路由激活时的 CSS 类名(默认 router-link-active

示例代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
  <nav>
    <!-- 基础用法 -->
    <router-link to="/home">首页</router-link>
    <!-- 带query参数URL中显示为?xxx=xxx -->
    <router-link to="{ path: '/article', query: { id: 123 } }">文章123</router-link>
    <!-- 带params参数需配合动态路由 -->
    <router-link to="{ name: 'Article', params: { id: 456 } }">文章456</router-link>
    <!-- replace属性替换历史记录 -->
    <router-link to="/login" replace>登录不保留历史</router-link>
    <!-- 自定义激活类名 -->
    <router-link to="/user" active-class="active">用户中心</router-link>
  </nav>
</template>

<style>
/* 路由激活时的样式 */
.active {
  color: #42b983;
  border-bottom: 2px solid #42b983;
}
</style>

编程式导航

通过 useRouter() 获取路由实例,调用实例方法实现跳转,适用于 “点击按钮后跳转” 等交互场景,常用方法包括:

  • push:新增历史记录并跳转(等同于 router-link 默认行为)
  • replace:替换当前历史记录并跳转(等同于 router-linkreplace 属性)
  • go:前进 / 后退指定步数(如 router.go(-1) 表示后退一页)

示例代码(组合式 API):

 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
<template>
  <button @click="goToArticle">查看文章</button>
  <button @click="replaceToLogin">去登录不保留历史</button>
  <button @click="goBack">后退</button>
</template>

<script setup>
import { useRouter } from 'vue-router';
const router = useRouter();

// 跳转至文章页(带params参数,需路由配置name)
const goToArticle = () => {
  router.push({
    name: 'Article', // 需在路由规则中配置name属性
    params: { id: 789 }
  });
};

// 替换历史记录跳转至登录页
const replaceToLogin = () => {
  router.replace('/login');
};

// 后退一页
const goBack = () => {
  router.go(-1);
};
</script>

动态路由实现

动态路由指 “在应用运行时,根据条件动态添加/删除路由规则”,适用于“权限控制”场景(如管理员可见的路由,普通用户不可见)。

动态添加路由

使用 router.addRoute() 方法动态添加路由,支持嵌套路由 (通过 parentName 指定父路由名称)。

示例代码:

 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
// 假设在登录后根据用户角色动态添加路由
const addAdminRoutes = () => {
  // 1. 定义管理员专属路由
  const adminRoutes = [
    {
      path: '/admin',
      name: 'Admin',
      component: () => import('@/views/Admin.vue'),
      meta: { requiresAuth: true, role: 'admin' },
      children: [
        { path: 'user-manage', component: () => import('@/views/Admin/UserManage.vue') },
        { path: 'log-manage', component: () => import('@/views/Admin/LogManage.vue') }
      ]
    }
  ];

  // 2. 动态添加路由
  adminRoutes.forEach(route => {
    router.addRoute(route);
  });
};

// 登录成功后调用(假设用户角色为admin)
const handleLogin = async () => {
  const { role } = await loginAPI(/* 登录参数 */);
  if (role === 'admin') {
    addAdminRoutes(); // 添加管理员路由
  }
};

动态删除路由

删除路由可通过以下方法:

  • router.removeRoute(routeName):通过路由名称删除
  • router.addRoute() 返回的函数:调用该函数删除对应路由

示例代码:

1
2
3
4
5
6
// 方法1:通过名称删除
router.removeRoute('Admin');

// 方法2:通过addRoute返回的函数删除
const removeRoute = router.addRoute({ path: '/temp', component: Temp });
removeRoute(); // 调用函数删除该路由

路由懒加载

路由懒加载 (Code Splitting) 指 “仅在路由被访问时才加载对应组件的代码”,可减少初始加载的 bundle 体积,提升应用启动速度。

Vue Router 中通过 “动态 import 语法” 实现。

实现方式

将路由规则中的 component 属性改为动态 import 函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const routes = [
  {
    path: '/home',
    // 懒加载Home组件,打包时会单独生成一个chunk文件
    component: () => import('@/views/Home.vue')
  },
  {
    path: '/article/:id',
    // 为懒加载的chunk命名(可选,便于调试)
    component: () => import(/* webpackChunkName: "article" */ '@/views/Article.vue')
  }
];

原理说明

  • 未使用懒加载时,所有组件代码会打包到一个 app.js 中,体积较大;
  • 使用懒加载后,每个组件会被打包为独立的 chunk(如 home.jsarticle.js);
  • 首次访问应用时,仅加载 app.js 和当前路由对应的 chunk;
  • 访问其他路由时,浏览器会动态请求对应的 chunk 并执行,实现 “按需加载”

总结

Vue3 路由 (Vue Router 4) 通过 Hash/History 模式实现无刷新导航,借助导航守卫控制路由权限,支持动态路由、嵌套路由、懒加载等特性,是构建 Vue3 单页应用的核心工具。 掌握其原理需理解:

  • 路由模式如何监听 URL 变化
  • 导航守卫如何拦截与控制跳转
  • 动态路由与懒加载如何优化应用性能

如果本文对您有所帮助,欢迎打赏支持作者!

Licensed under CC BY-NC-SA 4.0
最后更新于 2025-10-23 16:35
使用 Hugo 构建
主题 StackJimmy 设计