Vue Router 是啥?单页应用为啥离不开它?
做单页应用开发时,路由管理总让人头大?页面跳转逻辑乱、权限控制难、动态页面适配差……Vue Router 作为 Vue 生态里专门管路由的工具,能帮我们把这些难题逐个击破,这篇文章用问答形式,把 Vue Router 从基础到实战的知识点拆明白,新手也能跟着理清思路~
单页应用(SPA)的核心是**只加载一次页面,后续“切换页面”靠 JavaScript 动态渲染组件**,但用户体验得像多页应用一样流畅(比如刷新、前进后退正常),Vue Router 干的事,*把 URL 变化和组件渲染做精准映射**——让 URL 变了,页面组件也跟着换,同时还能管理页面状态、历史记录这些细节。举个例子:做个博客 SPA,点击“关于我”时,URL 从 变成 /about,页面自动渲染 About 组件,要是没路由,要么页面刷新体验差,要么得自己写一堆逻辑监听 URL、手动切换组件,麻烦到哭,对比多页应用(每次跳转都刷新整页),SPA 靠路由实现“单页内的多视图切换”,既保流畅性又省资源,而 Vue Router 就是这套逻辑的“指挥官”。
从零开始,怎么给 Vue 项目配好路由?
想让路由跑起来,分安装、配规则、挂到根实例三步:
第一步:装依赖
打开终端,在 Vue 项目里执行 npm install vue-router(如果用 Vue CLI 初始化项目时选了“路由”,这步会自动完成)。
第二步:写路由规则
新建 router/index.js 文件,导入 Vue、VueRouter 和要映射的组件,再定义路由规则:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/components/Home.vue' // 导入首页组件
import About from '@/components/About.vue' // 导入关于页组件
Vue.use(VueRouter) // 注册路由插件,让 Vue 能识别路由相关语法
// 定义路由规则:path 是 URL 路径,component 是对应组件
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
// 创建路由实例,把规则传进去
const router = new VueRouter({ routes })
export default router // 导出路由实例,给 main.js 用
第三步:挂到 Vue 根实例
打开 main.js,把路由实例注入 Vue 根实例,让所有组件都能访问路由功能:
import Vue from 'vue'
import App from './App.vue'
import router from './router' // 导入上面写的路由配置
new Vue({
router, // 把路由实例注入,所有组件可通过 this.$router 调用路由方法
render: h => h(App)
}).$mount('#app')
在 App.vue 里加 <router-view></router-view>(这是“路由出口”,匹配的组件会渲染到这里),再用 <router-link to="/">首页</router-link> 这类标签做导航,一个基础路由就跑通啦~
页面跳转有门道,声明式和编程式导航咋选?
页面跳转分声明式(用
声明式导航:适合模板里的“静态导航”
在模板里写导航时,用 <router-link> 最方便,比如导航栏、菜单:
<router-link to="/">首页</router-link> <router-link to="/about">lt;/router-link>
Vue 会把它渲染成 <a> 标签,点击自动跳转,还能自动加“激活样式”(配了 activeClass 的话),不用自己写点击事件。
编程式导航:适合逻辑里的“动态跳转”
在 JavaScript 逻辑里跳转(比如按钮点击后判断权限再跳),用 this.$router 的方法,最常用的是 push:
methods: {
submitForm() {
// 假设表单验证通过,跳转到结果页
this.$router.push('/success')
}
}
除了 push,还有 replace(替换当前历史记录,后退时回不去)、go(类似 history.go,控制前进/后退步数)。
简单说:模板里的导航用声明式,逻辑里的跳转用编程式,各司其职更清爽~
动态路由、嵌套路由,复杂页面咋拆分?
实际项目里,页面不可能只有平级的“首页/关于页”,还得处理动态页面(如商品详情)和多层嵌套(如后台管理页的子页面)。
动态路由:复用组件,按参数变内容
比如电商 App 的商品详情页,每个商品 URL 是 /product/123、/product/456,但都用同一个 Product 组件,这时用动态段(:id)配路由:
{ path: '/product/:id', component: Product }
组件里通过 this.$route.params.id 拿到当前商品 ID,再发请求拿对应数据,这样不用给每个商品写新路由,一个组件复用到底,省代码又好维护。
嵌套路由:拆分多层页面结构
比如后台管理页面 /dashboard,点侧边栏“订单”跳 /dashboard/order,点“分析”跳 /dashboard/analysis,这种“父页面套子页面”的结构,用嵌套路由:
{
path: '/dashboard',
component: Dashboard, // 父组件
children: [ // 子路由数组
{ path: 'order', component: Order },
{ path: 'analysis', component: Analysis }
]
}
父组件 Dashboard.vue 里得放 <router-view></router-view>,子路由匹配的组件(Order、Analysis)会渲染到这里,这样页面结构分层清晰,和组件化思想一脉相承~
路由守卫是干啥的?权限控制、页面拦截全靠它?
路由守卫像“路由的门卫”,在路由跳转前、后做事情(比如权限验证、数据预加载、页面拦截),它分三类:全局守卫(管整个应用的路由)、路由独享守卫(只管某个路由)、组件内守卫(组件自己生命周期里管)。
全局守卫:router.beforeEach
最常用的是全局前置守卫 beforeEach,跳转前触发,比如判断用户是否登录,没登录就拦截到登录页:
router.beforeEach((to, from, next) => {
// to: 要跳去的路由;from: 从哪个路由来;next: 放行/跳转的函数
const isLogin = localStorage.getItem('token') // 假设用 token 判断登录
if (to.path === '/login') {
next() // 去登录页,直接放行
} else {
isLogin ? next() : next('/login') // 没登录就跳登录页
}
})
还有全局后置守卫 afterEach,跳转后触发,适合改页面标题、埋点统计。
路由独享守卫:beforeEnter
给单个路由配守卫,比如某个敏感页面,除全局验证外还要额外检查:
{
path: '/secret',
component: Secret,
beforeEnter: (to, from, next) => {
// 这里写针对 /secret 的权限逻辑
const hasPermission = checkPermission()
hasPermission ? next() : next('/403')
}
}
组件内守卫:beforeRouteEnter 等
组件里的守卫,比如进入组件前加载数据:
export default {
beforeRouteEnter(to, from, next) {
// 这里还拿不到 this(组件实例没创建),发请求放 next 里
axios.get('/data').then(res => {
next(vm => { // vm 是组件实例
vm.data = res.data
})
})
},
beforeRouteUpdate(to, from, next) {
// 路由参数变了,但组件复用(如动态路由 /product/:id 从 123 变 456)
this.fetchData(to.params.id)
next()
}
}
组件内守卫能精细控制组件和路由的交互,处理数据加载、参数变化很方便~
开发时碰到路由 bug,常见坑咋避?
路由用顺了也会遇“玄学问题”,提前避坑省头发:
坑 1:history 模式下刷新页面 404
Vue Router 有 hash(URL 带 #,如 xxx.com/#/about)和 history(URL 干净,如 xxx.com/about)两种模式,用 history 时,服务器得配置 fallback(所有请求落到 index.html),否则用户刷新会因服务器找不到 /about 返回 404。
解决:nginx 加 try_files $uri $uri/ /index.html;,或结合 Vue CLI 的 publicPath 配服务器规则,确保请求都指向 index.html。
坑 2:动态路由参数变了,组件不刷新
比如从 /product/123 跳 /product/456,因组件复用(同个 Product 组件),Vue 不销毁重建,生命周期钩子(如 created)不执行,数据不更新。
解决:用 watch $route 或 beforeRouteUpdate 监听参数变化,重新拉数据:
watch: {
'$route' (to) {
this.fetchData(to.params.id)
}
}
// 或用 beforeRouteUpdate
beforeRouteUpdate(to, from, next) {
this.fetchData(to.params.id)
next()
}
坑 3: 激活样式不生效
想让当前路由的
解决:加 exact 属性开精确匹配:
<router-link to="/" exact>首页</router-link>
这样只有 URL 完全等于 时才激活~
实战案例:用 Vue Router 搭个简易博客 SPA
光看理论不够,动手做个小项目更扎实,需求:做个博客,有首页(列表)、文章详情页、分类页,还要用路由守卫做权限控制(假设“草稿文章”需登录才能看)。
步骤 1:项目初始化 + 装路由
用 Vue CLI 新建项目,选上 Vue Router,结构里 router/index.js 配路由,views 文件夹放页面级组件(Home、Post、Category)。
步骤 2:配路由规则
const routes = [
{ path: '/', component: Home },
{
path: '/post/:id',
component: Post,
beforeEnter: (to, from, next) => { // 路由独享守卫,判断是否草稿
const post = getPostById(to.params.id) // 假设拿文章数据的函数
if (post.isDraft && !isLogin()) {
next('/login') // 草稿且没登录,跳登录
} else {
next()
}
}
},
{ path: '/category/:name', component: Category },
{ path: '/login', component: Login }
]
步骤 3:写组件逻辑
- Home.vue:用假数据渲染文章列表,每个文章项用
<router-link :to="'/post/'+post.id">跳详情页。 - Post.vue:通过
this.$route.params.id拿文章 ID,发请求(或读假数据)渲染内容。 - Category.vue:通过
this.$route.params.name拿分类名,渲染对应文章列表。
步骤 4:加全局守卫控制登录
在 router/index.js 里加全局前置守卫,判断非登录页且没 token 时跳登录:
router.beforeEach((to, from, next) => {
const isLogin = localStorage.getItem('token')
if (to.path !== '/login' && !isLogin) {
next('/login')
} else {
next()
}
})
步骤 5:测试流程
- 访问首页,点文章跳详情:草稿文章会被拦截到登录页,登录后(存 token 到 localStorage)再跳回去能看。
- 点分类,URL 变
/category/前端,页面渲染前端分类文章。 - 登录页输账号密码(模拟存 token),跳转后能正常访问受限页面。
这个小项目把路由配置、动态路由、守卫、导航方式全练了一遍,做完对 Vue Router 就有数啦~
Vue Router 是 SPA 开发的“导航中枢”,从基础配置到复杂场景,掌握路由映射、导航方式、守卫机制这些点,能让单页应用的页面管理更丝滑,多练案例、踩踩坑,遇到问题翻翻官方文档(Vue Router 文档讲得超细!),自然就熟了~下次做 SPA 时,路由这块心里就有底啦~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。