前端八股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)、嵌套路由(后台管理系统)"

相关推荐
mldong4 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排4 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60615 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角6 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!6 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰6 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi8 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen8 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马9 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu9 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss