前端八股Vue---Vue-router路由管理器

目录

[一、Vue-Router 是什么?](#一、Vue-Router 是什么?)

[传统多页应用 vs 单页应用](#传统多页应用 vs 单页应用)

二、核心概念

[三、基础使用(Vue 3)](#三、基础使用(Vue 3))

[1. 安装](#1. 安装)

[2. 配置路由](#2. 配置路由)

[history 模式对比](#history 模式对比)

[3. 注册路由](#3. 注册路由)

[4. 模板中使用](#4. 模板中使用)

四、动态路由匹配

五、嵌套路由

路由配置(三层嵌套)

[2. 第一层父组件:UserLayout](#2. 第一层父组件:UserLayout)

[3. 第二层父组件:UserProfile(个人资料布局)](#3. 第二层父组件:UserProfile(个人资料布局))

六、编程式导航

七、路由守卫

[1. 全局前置守卫(最常用)](#1. 全局前置守卫(最常用))

[2. 全局后置守卫](#2. 全局后置守卫)

[3. 路由独享守卫](#3. 路由独享守卫)

[4. 组件内守卫](#4. 组件内守卫)

八、路由模式对比

九、路由懒加载

十、面试回答


Vue-Router 是 Vue.js 的官方路由管理器 ,用于构建单页应用(SPA),通过管理 URL 与组件的映射关系,实现页面切换而不刷新浏览器。


一、Vue-Router 是什么?

传统多页应用 vs 单页应用

对比 多页应用 (MPA) 单页应用 (SPA)
页面切换 刷新整个页面 无刷新,局部更新
路由方式 发送 HTTP 请求 前端路由(hash/history)
用户体验 有白屏,体验差 流畅,体验好
SEO 较差(需 SSR)

Vue-Router 的作用:在 SPA 中,根据 URL 的变化,渲染对应的组件,实现"页面切换"的体验。


二、核心概念

复制代码
用户访问 /users
       │
       ▼
Vue-Router 匹配路由规则
       │
       ▼
渲染 Users 组件到 <router-view />
概念 说明
<router-link> 声明式导航,生成可点击的链接
<router-view> 路由出口,匹配到的组件渲染在这里
routes 路由配置数组,定义路径与组件的映射
router.push() 编程式导航,JS 跳转页面
路由守卫 导航过程中的钩子函数

三、基础使用(Vue 3)

1. 安装

复制代码
npm install vue-router@4

2. 配置路由

javascript 复制代码
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'

const routes = [   //存储路由,每个路由是一个对象
  {
    path: '/',    //用户访问的路径
    name: 'Home',  //路由名称(可选,用于命名路由)
    component: Home   //匹配后渲染的组件
  },   //用户访问根路径 / 时,<router-view /> 中显示 Home.vue 组件。
  {
    path: '/about',
    name: 'About',
    component: About
  },
  {
    path: '/user/:id',  // 动态路由
    name: 'User',
    component: () => import('@/views/User.vue')  // 懒加载(访问 /user/:id 时才加载 User.vue)
  }
]

const router = createRouter({    //创建路由实例
  history: createWebHistory(),  // HTML5 模式
  routes
})

export default router   //导出路由

routes 数组 :定义 URL 路径与组件的映射关系。每个路由对象包含 path(路径)、name(名称)、component(组件)。

动态路由/user/:id 中的 :id 是占位符,可以匹配 /user/1/user/123 等,通过 route.params.id 获取参数。

懒加载() => import('...') 让组件在访问时才加载,减少首屏体积。

createRouter :创建路由实例,配置历史模式(createWebHistory 是干净 URL)。

导出后 :在 main.js 中通过 app.use(router) 注册,应用才能使用路由功能。

history 模式对比
模式 URL 示例 说明
createWebHistory() http://localhost:5173/about 干净 URL,需要服务器配置
createWebHashHistory() http://localhost:5173/#/about #,无需服务器配置

需要服务器配置是指:使用 History 模式时,刷新页面或直接访问子路径,服务器需要返回 index.html 而不是 404。

原因 :SPA 只有一个真实的 index.html,所有路由都是前端模拟的。Hash 模式下 # 后面的内容不发送给服务器,所以没问题。History 模式下浏览器会真实请求 /about 路径,服务器需要把所有请求都指向 index.html,让前端路由处理。

解决方案 :配置 Nginx 的 try_files $uri $uri/ /index.html;,或 Apache 的 mod_rewrite,或 Node.js 的 app.get('*', ...)

开发环境:Vite/Webpack 自动处理,无需配置。

打包部署到生产服务器(如 Nginx)时,需要手动配置;如果使用 Vercel、Netlify 等平台,它们也自动处理了

3. 注册路由

javascript 复制代码
// main.js :Vue 应用的入口文件
import { createApp } from 'vue'
import App from './App.vue'  //导入根组件,整个应用的入口组件
import router from './router'   // 导入上面导出的 router

const app = createApp(App)  //创建 Vue 应用实例
app.use(router)  // 注册路由
app.mount('#app') //挂载

4. 模板中使用

javascript 复制代码
<template>
  <div>
    <!-- 声明式导航 -->
    <router-link to="/">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-link :to="{ name: 'User', params: { id: 123 } }">用户123</router-link>
    
    <!-- 路由出口 -->
    <router-view />
  </div>
</template>

<router-link><router-view> 是 Vue-Router 的核心组件。

<router-link> :声明式导航,渲染成 <a> 标签。to 属性指定跳转路径,支持字符串或对象。:to 用于动态绑定,可以传对象和变量。点击时自动更新 URL,不会刷新页面。

<router-view>:路由出口,匹配到的组件会渲染在这里。一个应用可以有一个或多个(命名视图)。

工作流程 :点击 <router-link> → URL 变化 → 匹配路由配置 → 找到组件 → 渲染到 <router-view>


四、动态路由匹配

javascript 复制代码
const routes = [
  // 动态路径参数 以冒号开头
  { path: '/user/:id', component: User },
  { path: '/post/:postId/comment/:commentId', component: Comment }
]
vue

<!-- 获取参数 -->
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()
console.log(route.params.id)  // 获取 URL 中的 id
</script>

五、嵌套路由

javascript 复制代码
const routes = [
  {
    path: '/user/:id',
    component: User,
    children: [
      {
        // 当 /user/:id/profile 匹配时
        path: 'profile',
        component: UserProfile
      },
      {
        // 当 /user/:id/posts 匹配时
        path: 'posts',
        component: UserPosts
      }
    ]
  }
]
javascript 复制代码
<!-- User.vue -->
<template>
  <div>
    <h1>用户页面</h1>
    <router-link to="profile">个人资料</router-link>
    <router-link to="posts">帖子</router-link>
    
    <!-- 嵌套路由出口 -->
    <router-view />
  </div>
</template>

路由配置(三层嵌套)

javascript 复制代码
// router/index.js
import UserLayout from '@/layouts/UserLayout.vue'
import UserProfile from '@/views/UserProfile.vue'
import ProfileBasic from '@/views/profile/ProfileBasic.vue'
import ProfilePassword from '@/views/profile/ProfilePassword.vue'
import ProfilePhone from '@/views/profile/ProfilePhone.vue'

const routes = [
  {
    path: '/user',
    component: UserLayout,  // 第一层父组件
    children: [
      {
        path: 'profile',     // /user/profile
        component: UserProfile,  // 第二层父组件
        children: [          // 👈 第三层:个人资料下的子路由
          {
            path: '',        // /user/profile → 默认显示基本信息
            component: ProfileBasic
          },
          {
            path: 'password',  // /user/profile/password
            component: ProfilePassword
          },
          {
            path: 'phone',     // /user/profile/phone
            component: ProfilePhone
          }
        ]
      },
      {
        path: 'posts',       // /user/posts
        component: UserPosts
      },
      {
        path: 'settings',    // /user/settings
        component: UserSettings
      }
    ]
  }
]

2. 第一层父组件:UserLayout

javascript 复制代码
<!-- layouts/UserLayout.vue -->
<template>
  <div class="user-layout">
    <h1>用户中心</h1>
    
    <!-- 第一层导航 -->
    <nav class="level1-nav">
      <router-link to="/user/profile">个人资料</router-link>
      <router-link to="/user/posts">我的帖子</router-link>
      <router-link to="/user/settings">账号设置</router-link>
    </nav>
    
    <!-- 第一层出口:显示个人资料/我的帖子/账号设置 -->
    <div class="level1-content">
      <router-view />
    </div>
  </div>
</template>

3. 第二层父组件:UserProfile(个人资料布局)

javascript 复制代码
<!-- views/UserProfile.vue -->
<template>
  <div class="user-profile">
    <h2>个人资料</h2>
    
    <!-- 第二层导航:个人资料下的子选项 -->
    <nav class="level2-nav">
      <router-link to="/user/profile">基本信息</router-link>
      <router-link to="/user/profile/password">修改密码</router-link>
      <router-link to="/user/profile/phone">绑定手机</router-link>
    </nav>
    
    <!-- 第二层出口:显示基本信息/修改密码/绑定手机 -->
    <div class="level2-content">
      <router-view />
    </div>
  </div>
</template>

<style scoped>
.level2-nav {
  margin: 15px 0;
  padding: 10px;
  background: #f5f5f5;
}
.level2-nav a {
  margin-right: 20px;
}
.level2-content {
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
}
</style>

六、编程式导航

方式 是什么 示例
声明式导航 <router-link> 标签,像写 HTML 一样声明跳转 <router-link to="/about">关于</router-link>
编程式导航 用 JavaScript 代码调用方法跳转 router.push('/about')
方法 作用 能否后退 示例
push() 添加新历史记录 ✅ 能 router.push('/about')
replace() 替换当前历史记录 ❌ 不能 router.replace('/about')
go() 前进/后退 N 步 - router.go(-1)
javascript 复制代码
<script setup>
import { useRouter } from 'vue-router'

const router = useRouter()

// 字符串路径
router.push('/users')

// 对象路径
router.push({ path: '/users' })

// 命名路由
router.push({ name: 'User', params: { id: 123 } })

// 带查询参数
router.push({ path: '/users', query: { page: 2 } })

// 替换当前历史记录(不能后退)
router.replace('/users')

// 前进/后退
router.go(1)   // 前进
router.go(-1)  // 后退
</script>

router.push() 有四种常用写法:

1. 字符串路径router.push('/users'),用于简单固定路径。

2. 对象路径router.push({ path: '/users' }),配合 query 传查询参数。

3. 命名路由router.push({ name: 'User', params: { id: 123 } }),用于动态路由(/user/:id),更安全,路径变化时不用改代码。

4. 带查询参数router.push({ path: '/users', query: { page: 2 } }),用于分页、搜索、筛选。

注意pathparams 不能一起用,要用 name 才能配合 params

  • 命名路由(name + params需要 路由配置中有 : 动态路径(如 /user/:id),params 会替换 : 占位符

  • 带查询参数(path + query不需要 路由配置 :query 会变成 URL 问号后的参数(如 ?page=2

路径参数(/user/:id :用来标识具体资源 ,回答'哪一个'的问题。用于详情页、编辑页等需要明确指定资源的场景。需要在路由配置中定义 : 占位符。

问号参数(/users?page=2 :用来筛选、排序、分页,回答'怎么展示'的问题。用于列表页、搜索页等需要控制展示方式的场景。不需要在路由配置中定义。

示例

  • /user/123 → 用户123的详情页(路径参数)

  • /users?page=2&keyword=vue → 搜索Vue的第2页(问号参数)

规范:资源标识用 params,资源属性用 query。


七、路由守卫

路由守卫 是 Vue Router 提供的导航过程中的钩子函数 ,可以在路由跳转的不同阶段 插入代码,实现权限控制、页面标题、加载进度、数据预获取等功能。

1. 全局前置守卫(最常用)

在路由跳转之前 触发,用于权限验证、登录检查

javascript 复制代码
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

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

// 全局前置守卫
router.beforeEach((to, from, next) => {
  // to:要去的路由对象
  // from:当前路由对象
  // next:放行函数
  
  const token = localStorage.getItem('token')
  
  // 需要登录的页面
  if (to.meta.requiresAuth && !token) {
    next({ name: 'Login', query: { redirect: to.fullPath } })
  } 
  // 已登录访问登录页,跳转首页
  else if (to.name === 'Login' && token) {
    next({ name: 'Home' })
  } 
  else {
    next()  // 放行
  }
})

2. 全局后置守卫

在路由跳转之后 触发,没有 next 参数,用于页面标题、埋点统计、关闭进度条

javascript 复制代码
// 全局后置守卫
router.afterEach((to, from) => {
  // 设置页面标题
  document.title = to.meta.title || '默认标题'
  
  // 关闭加载进度条
  NProgress.done()
  
  // 埋点统计
  if (window.gtag) {
    window.gtag('config', 'UA-XXXXX-Y', { page_path: to.fullPath })
  }
  
  // 滚动到顶部
  window.scrollTo(0, 0)
})

3. 路由独享守卫

只在特定路由中定义,只对该路由生效。

javascript 复制代码
const routes = [
  {
    path: '/admin',
    name: 'Admin',
    component: Admin,
    meta: { requiresAuth: true, role: 'admin' },
    beforeEnter: (to, from, next) => {
      // 只在这个路由生效
      const userRole = localStorage.getItem('role')
      if (userRole === 'admin') {
        next()
      } else {
        next({ name: 'Forbidden' })
      }
    }
  }
]

4. 组件内守卫

在组件内部定义,与组件生命周期结合。

javascript 复制代码
<script>
export default {
  // 1. 进入组件前(组件实例还没创建,不能访问 this)
  beforeRouteEnter(to, from, next) {
    // 不能访问 this
    console.log('beforeRouteEnter', to.params.id)
    
    // 可以通过 next 回调访问组件实例
    next(vm => {
      // vm 是组件实例
      vm.fetchData()
    })
  },
  
  // 2. 路由参数变化时(如 /user/1 → /user/2)
  beforeRouteUpdate(to, from, next) {
    // 可以访问 this
    console.log('beforeRouteUpdate', to.params.id)
    this.userId = to.params.id
    this.fetchData()
    next()
  },
  
  // 3. 离开组件前(防止未保存的更改丢失)
  beforeRouteLeave(to, from, next) {
    // 可以访问 this
    if (this.hasUnsavedChanges) {
      const answer = confirm('有未保存的更改,确定离开吗?')
      answer ? next() : next(false)
    } else {
      next()
    }
  }
}
</script>

八、路由模式对比

模式 实现方式 URL 示例 兼容性 适用场景
hash URL 的 hash 值 /#/users 所有浏览器 无需服务端配置
history HTML5 History API /users IE10+ 需要服务端配置
javascript 复制代码
// hash 模式
const router = createRouter({
  history: createWebHashHistory()
})

// history 模式(推荐)
const router = createRouter({
  history: createWebHistory()
})
history 模式需要服务端配置(否则刷新 404):

nginx

# Nginx 配置
location / {
  try_files $uri $uri/ /index.html;
}

九、路由懒加载

javascript 复制代码
// 非懒加载(首屏一次性加载所有页面)
import Home from '@/views/Home.vue'

// 懒加载(访问时才加载)
const Home = () => import('@/views/Home.vue')

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: () => import('@/views/About.vue') }
]

十、面试回答

"Vue-Router 是 Vue 的官方路由管理器,用于构建单页应用。

核心功能

  • 管理 URL 与组件的映射关系

  • 提供 <router-link> 声明式导航和 router.push() 编程式导航

  • 通过 <router-view> 渲染匹配的组件

两种模式

  • hash 模式:URL 带 #,兼容性好,无需服务端配置

  • history 模式:URL 干净,需要服务端配置

路由守卫beforeEach(全局前置)、afterEach(全局后置)、beforeEnter(路由独享)

懒加载() => import('@/views/Home.vue'),减少首屏体积

常用场景 :权限验证(路由守卫中检查登录状态)、动态路由(/user/:id)、嵌套路由(后台管理系统)"

相关推荐
百锦再2 小时前
Auto.js变成基础知识学习
开发语言·javascript·学习·sqlite·kotlin·android studio·数据库开发
洛_尘3 小时前
Python 5:使用库
java·前端·python
Bigger3 小时前
Bun 能上生产吗?我的实战结论
前端·node.js·bun
kyriewen4 小时前
你的前端滤镜慢得像PPT?用Rust+WebAssembly,一秒处理4K图
前端·rust·webassembly
kyriewen114 小时前
你等的Babel编译,够喝三杯咖啡了——用Rust重写的SWC,只需眨个眼
开发语言·前端·javascript·后端·性能优化·rust·前端框架
IT_陈寒5 小时前
SpringBoot自动配置坑了我,原来要这样绕过去
前端·人工智能·后端
东方小月5 小时前
Claude Code 完整上手指南:MCP、Skills、第三方模型配置一次搞定
前端·人工智能·后端
XZ探长5 小时前
基于 Trae Solo 移动办公修复 Vue3 前端服务问题
前端
逍遥德5 小时前
AI时代,计算机专业大学生学习指南
java·javascript·人工智能·学习·ai编程