news 2026/6/8 13:52:07

Vue Router 从0到会用:手摸手带你搞懂前端路由,每行代码都有注释》

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue Router 从0到会用:手摸手带你搞懂前端路由,每行代码都有注释》

Vue Router 从0到会用:手摸手带你搞懂前端路由,每行代码都有注释

一、没有路由之前,页面跳转是怎样的?

先回忆一下最原始的多页面网站是怎么跳转的:

你点了导航栏里的“关于我们”,浏览器就向服务器发一个请求,服务器返回一个全新的HTML页面,整个页面都刷新了。白屏一下,再加载,体验很差。

后来有了单页应用(SPA):整个网站其实只有一个HTML页面,所有“换页面”的效果,本质上是JavaScript在偷偷地切换显示的组件,并没有真正跳转到新页面。

Vue Router就是Vue官方提供的、专门管这个“组件切换”的工具。


二、先搭一个能跑的Vue项目

如果你还没创建过Vue项目,跟着做:

bash

# 1. 创建项目,项目名随便取,这里叫 my-router-demo npm create vue@latest my-router-demo # 2. 进入项目文件夹 cd my-router-demo # 3. 安装依赖 npm install # 4. 启动开发服务器 npm run dev

注意:创建过程中会问你一堆要不要装的东西。看到 Router 那项,选 Yes,其他的可以先不管。这样创建出来的项目已经自带路由了,省去手动装的步骤。

如果创建时忘了勾Router,就手动装一下:

bash

npm install vue-router@4

三、路由到底在干什么?一张图看懂

在你浏览器地址栏里输一个地址,比如/home,Vue Router就去找一张“对照表”,看/home应该显示哪个组件,然后把那个组件渲染到指定位置。

text

浏览器地址栏: /home ——> 显示 Home组件 浏览器地址栏: /about ——> 显示 About组件 浏览器地址栏: /user/123 ——> 显示 User组件,并且能拿到123这个参数

这张“对照表”就是路由配置,也就是路由表。


四、最小化例子:两个页面的路由

先看项目里创建时自动生成的目录结构(只关注几个重要的):

text

src/ ├── router/ │ └── index.js ← 路由配置文件,路由表在这 ├── views/ │ ├── HomeView.vue ← 首页组件 │ └── AboutView.vue ← 关于页组件 ├── App.vue ← 根组件 └── main.js ← 入口文件

1. 路由配置文件src/router/index.js长这样

javascript

// 第一步:从vue-router包里引入需要的函数 // createRouter: 创建路由实例 // createWebHistory: 使用HTML5的History模式(地址栏没有#号,更像普通网页) import { createRouter, createWebHistory } from 'vue-router' // 第二步:引入要用到的组件(这些就是不同“页面”) // @ 是src目录的别名,写 @/views/xxx 等于写 src/views/xxx import HomeView from '@/views/HomeView.vue' import AboutView from '@/views/AboutView.vue' // 第三步:定义路由表(就是那张“对照表”) // 每条路由记录是一个对象,包含path(路径)和component(对应的组件) const routes = [ { path: '/', // 访问根路径 / 时 name: 'home', // 给这条路由起个名字,方便后面用 component: HomeView // 显示HomeView这个组件 }, { path: '/about', // 访问 /about 时 name: 'about', // 名字 component: AboutView // 显示AboutView组件 } ] // 第四步:创建路由实例 const router = createRouter({ history: createWebHistory(), // 用History模式,地址栏干净 routes: routes // 把刚才定义的路由表传进去 }) // 第五步:导出路由实例,给main.js用 export default router

2. 入口文件src/main.js里挂载路由

javascript

import { createApp } from 'vue' import App from './App.vue' import router from './router' // 引入刚才写的路由文件 const app = createApp(App) // 这一行很关键:把路由实例挂到Vue应用上 // 这样所有组件里都能用路由的功能 app.use(router) app.mount('#app') // 挂载到index.html里的#app元素上

3. 根组件App.vue里指定“出口”

vue

<template> <div id="app"> <!-- 导航栏,点击切换路由 --> <nav> <!-- <router-link> 是Vue Router提供的组件,用来生成导航链接 to属性指定目标路径,点击后地址栏变成对应的path 浏览器里它会被渲染成一个<a>标签 --> <router-link to="/">首页</router-link> <router-link to="/about">关于</router-link> </nav> <!-- 这是最重要的东西:router-view 它就像一个占位符,当前匹配到的路由组件就渲染在这里 访问/时,这里渲染HomeView 访问/about时,这里渲染AboutView 其他内容(比如上面的nav)不会变,只有这里会切换 --> <router-view /> </div> </template>

到这里,你已经有了两个“页面”的应用。在浏览器里点首页和关于,你会发现地址栏变了,但页面没有整体刷新,只有<router-view />那块区域在切换。这就是单页应用的感觉。


五、动态路由:同一个组件,根据参数显示不同内容

比如用户详情页,/user/1显示用户1的信息,/user/2显示用户2的信息。用的是同一个组件,只是参数不同。

1. 路由配置加个动态参数

javascript

// router/index.js 里加一条 const routes = [ // ... 前面的路由 ... { // :id 表示这部分是动态的,会匹配 /user/1、/user/2、/user/abc 等 // 冒号后面的id是你给这个参数起的名字 path: '/user/:id', name: 'user', component: () => import('@/views/UserView.vue') // 上面用的是懒加载:只有访问到这个路由时,才去下载组件代码 // import()返回一个Promise,Vue Router会自动处理 } ]

2. UserView.vue 里获取动态参数

vue

<template> <div> <!-- 通过 $route.params 获取路径里的参数 $route 是当前路由的信息对象,Vue Router自动提供 .params 是一个对象,里面包含所有动态参数 我们在路由里定义了 :id,所以这里用 $route.params.id 取值 --> <h1>用户详情页</h1> <p>当前用户ID:{{ $route.params.id }}</p> </div> </template> <script setup> // 在script里想获取路由参数,用 useRoute 这个函数 import { useRoute } from 'vue-router' // useRoute() 返回当前路由的信息对象,等同于模板里的 $route const route = useRoute() // 打印一下看看里面有什么 console.log('当前路径参数:', route.params) console.log('用户ID:', route.params.id) // route.params.id 就是路径里 :id 匹配到的值 </script>

试试:浏览器访问/user/123,页面上显示ID是123;改成/user/456,显示ID变成456。组件是同一个,数据跟着URL变。


六、编程式导航:用代码跳转,不用router-link

有时候你不能用<router-link>,比如填完表单点提交,验证通过后再跳转。这就要在JS代码里控制跳转。

vue

<template> <div> <h2>登录页</h2> <button @click="goToHome">登录成功,去首页</button> <button @click="goToUser">查看用户123</button> <button @click="goBack">返回上一页</button> </div> </template> <script setup> // useRouter 用来拿到路由实例,用它进行跳转 import { useRouter } from 'vue-router' const router = useRouter() // 拿到路由实例 function goToHome() { // push方法:跳转到指定路径,会留下历史记录(可以点浏览器后退) // 参数可以是路径字符串 router.push('/') } function goToUser() { // 也可以传一个对象,用name指定路由名,用params传参 // 这种方式更灵活,路径变了代码不用改 router.push({ name: 'user', // 跳转到name为'user'的路由 params: { id: '123' } // 传参数,对应路由里定义的 :id }) } function goBack() { // back方法:返回上一页,等同于浏览器的后退按钮 router.back() } </script>

push和replace的区别

  • push('/home'):跳转后会留下历史记录,用户能点返回。

  • replace('/home'):跳转后替换当前历史记录,用户点返回回不来。适合登录成功后跳转,不让用户退回登录页。


七、嵌套路由:页面里面还有子页面

很多后台管理系统是这样的布局:

  • 左边侧边栏不变

  • 顶部导航不变

  • 中间内容区随着菜单点击而切换

这就是嵌套路由的典型场景。

1. 路由配置写 children

javascript

// router/index.js const routes = [ { path: '/admin', component: () => import('@/views/AdminLayout.vue'), // children定义子路由,匹配 /admin/xxx 的路径 children: [ { path: '', // 空字符串,访问 /admin 时默认显示 name: 'admin-dashboard', component: () => import('@/views/admin/Dashboard.vue') }, { path: 'users', // 注意不用写斜杠,实际匹配 /admin/users name: 'admin-users', component: () => import('@/views/admin/UserList.vue') }, { path: 'settings', // 匹配 /admin/settings name: 'admin-settings', component: () => import('@/views/admin/Settings.vue') } ] } ]

2. AdminLayout.vue 里面再放一个router-view

vue

<template> <div class="admin-layout"> <!-- 侧边栏,导航到子路由 --> <aside class="sidebar"> <h3>后台管理</h3> <ul> <li><router-link to="/admin">仪表盘</router-link></li> <li><router-link to="/admin/users">用户管理</router-link></li> <li><router-link to="/admin/settings">系统设置</router-link></li> </ul> </aside> <!-- 右侧内容区 --> <main class="content"> <!-- 第二个router-view,用来显示子路由对应的组件 /admin 时显示 Dashboard /admin/users 时显示 UserList 以此类推 --> <router-view /> </main> </div> </template>

嵌套路由的逻辑就是:父组件里放一个<router-view />,子路由匹配到的组件就渲染在那个位置。


八、路由守卫:在跳转前做点什么

比如有些页面必须登录后才能访问,没登录就跳到登录页。这叫路由守卫

全局前置守卫:所有路由跳转前都会触发

javascript

// router/index.js 里,创建router实例之后加 router.beforeEach((to, from, next) => { // 三个参数: // to:要去的路由信息(包含path、params等) // from:从哪个路由来的 // next:必须调用,否则路由不会继续跳转 // 假设你有一个简单的方法判断是否登录 const isLoggedIn = localStorage.getItem('token') // 有token就认为已登录 // 如果要去的是需要登录的页面(这里以meta.requiresAuth标记) if (to.meta.requiresAuth && !isLoggedIn) { // 没登录,跳到登录页 next('/login') } else { // 其他情况正常放行 next() // 不加参数就是正常跳转 } })

在路由配置里标记哪些需要登录

javascript

const routes = [ { path: '/admin', component: () => import('@/views/AdminLayout.vue'), // meta是路由的元信息,随便放自定义数据 meta: { requiresAuth: true }, // 标记这个路由需要登录 children: [ // ...子路由 ] }, { path: '/login', name: 'login', component: () => import('@/views/LoginView.vue') } ]

九、常见小问题,我踩过的坑

1. 路由变了但组件没重新渲染

有时候从/user/1跳到/user/2,组件是同一个,Vue会复用组件,created钩子不会再次触发。如果你依赖created去请求数据,数据就还是旧的。

解决办法:用 watch 监听路由变化:

javascript

import { watch } from 'vue' import { useRoute } from 'vue-router' const route = useRoute() // 监听路由参数变化,变化了就重新请求数据 watch( () => route.params.id, // 监听params里的id (newId) => { console.log('ID变了,新ID:', newId) fetchUserData(newId) // 重新获取数据 } )

2. 加了history模式,刷新页面404

createWebHistory()时,地址栏是干净的(没有#号)。但如果你直接访问/about然后刷新页面,浏览器会真的向服务器请求/about这个路径,而服务器上根本没有这个文件,就404了。

解决办法:开发环境下Vite已经帮你处理好了。上线时需要在Nginx里加配置,把所有的请求都指向index.html

3. router-link点击后没有样式

router-link默认渲染成a标签,当它匹配到当前路由时,Vue Router会自动给它加上两个class:router-link-activerouter-link-exact-active。你可以在CSS里给这两个类加样式,实现高亮当前菜单的效果。

css

/* 精确匹配时(比如 / 对 /,/about 对 /about) */ .router-link-exact-active { color: #1890ff; font-weight: bold; } /* 模糊匹配时(比如 /admin/users 和 /admin 也算匹配) */ .router-link-active { background: #f0f0f0; }

十、总结一下你学到的

概念干什么用的关键代码
路由表定义路径和组件的对应关系routes: [{path:'/xxx', component: Xxx}]
router-view指定组件渲染的位置<router-view />
router-link生成导航链接<router-link to="/xxx">
动态路由同一个组件,参数不同path: '/user/:id',取值$route.params.id
编程式导航用JS代码跳转router.push('/xxx')
嵌套路由页面里还有子页面配置里写children,组件里放<router-view />
路由守卫跳转前做检查(如登录)router.beforeEach((to, from, next)=>{})

写在最后

Vue Router刚开始学,最容易迷惑的就是哪个组件在哪渲染。记住一个原则:

<router-view />在哪,组件就渲染在哪。

App.vue里那个是顶级出口,用来渲染所有一级路由。嵌套路由就是在父组件里再加一个<router-view />,渲染子路由。

多敲几个路由配置,切换来切换去,慢慢就习惯了。有问题评论区直接问,看到就回你。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/8 13:50:02

novel-downloader实战指南:5步打造你的专属小说下载规则

novel-downloader实战指南&#xff1a;5步打造你的专属小说下载规则 【免费下载链接】novel-downloader 一个可扩展的通用型小说下载器。 项目地址: https://gitcode.com/gh_mirrors/no/novel-downloader 你是否曾经想下载喜欢的小说却发现网站不支持&#xff1f;或者面…

作者头像 李华
网站建设 2026/6/8 13:44:13

网盘直链下载助手:9大主流网盘免费高速下载的终极解决方案

网盘直链下载助手&#xff1a;9大主流网盘免费高速下载的终极解决方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / …

作者头像 李华
网站建设 2026/6/8 13:43:25

抖音无水印下载终极指南:5分钟快速掌握douyin-downloader

抖音无水印下载终极指南&#xff1a;5分钟快速掌握douyin-downloader 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback su…

作者头像 李华
网站建设 2026/6/8 13:37:36

8位MCU嵌入式开发:数据结构精简设计与汇编级优化实践

1. 项目概述与核心价值在资源捉襟见肘的8位微控制器世界里&#xff0c;每一字节的RAM和每一个CPU周期都弥足珍贵。很多从高级语言或大型系统转过来的开发者&#xff0c;常常会下意识地引入一些“重量级”的数据结构库或复杂算法&#xff0c;结果往往是程序瞬间“爆”掉了本就有…

作者头像 李华
网站建设 2026/6/8 13:37:19

i.MX 8QuadMax功耗实测:从数据手册到电源与热设计实战

1. 项目概述&#xff1a;为什么我们要深挖i.MX 8QuadMax的功耗数据&#xff1f;在嵌入式系统&#xff0c;尤其是汽车电子和高端信息娱乐系统的开发中&#xff0c;选型一颗处理器&#xff0c;我们看重的绝不仅仅是它的主频和核心数量。一个经常被提及但数据又往往语焉不详的关键…

作者头像 李华