一、Vue Router Object 是个啥?
p>做Vue项目开发时,路由功能几乎是刚需,但很多同学刚接触Vue Router,对「Vue Router Object」总是一知半解:它到底是什么?怎么在组件里调用?动态路由、权限控制这些场景怎么靠它实现?今天咱们就把这个Vue路由的核心对象拆开讲,从基础概念到实战避坑,一次性搞懂!
你可以把它理解成整个Vue项目的“路由大管家”——所有路由规则、页面跳转逻辑、当前路由状态,都由这个对象统一管理。
先看创建它的代码:
// router.js 文件 import { createRouter, createWebHistory } from 'vue-router' import Home from './views/Home.vue' const routes = [ { path: '/', component: Home }, { path: '/about', component: () => import('./views/About.vue') } ] // 这里创建的 router Vue Router Object! const router = createRouter({ history: createWebHistory(), // 路由模式(history/hash) routes // 路由规则数组 }) export default router
这个router
对象一旦创建,就会成为单例(整个项目就这一个),负责:
- 存储所有路由规则(比如对应Home组件,
/about
对应About组件); - 提供「跳转页面」「前进后退」这些方法(像
router.push
、router.go
); - 记录当前路由状态(比如现在在哪个页面、URL里的参数是啥,对应
router.currentRoute
); - 处理导航守卫(比如页面跳转前判断用户是否登录,对应
router.beforeEach
)。
简单说:它是Vue Router的“心脏”,路由功能的方方面面都得靠它运转。
Vue Router Object 有哪些核心“技能”?
要用好这个大管家,得先摸清它的核心属性和方法,可以分成“状态属性”和“操作方法”两类。
核心属性:看状态
-
router.currentRoute
:当前路由的详细信息(响应式的!),比如你在/user/123?tab=info
页面,它会包含:{ path: '/user/123', params: { id: '123' }, query: { tab: 'info' }, name: 'user', // 路由命名的话才有 meta: { ... } // 路由元信息 }
在组件里,用
useRoute()
(组合式API)或this.$route
(选项式API)能拿到这个对象,而且它会自动响应式更新(参数变了、路径变了,它也会变)。 -
router.options
:创建路由时的“原始配置”,比如你初始化时传的routes
数组、history
模式,都存在这里,一般调试或动态路由时会用到。
核心方法:做操作
路由跳转、动态加路由、前进后退…全靠这些方法:
-
router.push()
:最常用的“跳转到新页面”,它会往浏览器历史栈里新增一条记录(点返回能回到上一页),用法灵活:// 方式1:直接写路径字符串 router.push('/user/123') // 方式2:命名路由 + 动态参数(推荐!解耦路径和参数) router.push({ name: 'user', params: { id: 123 } }) // 方式3:带查询参数(?后面的部分) router.push({ path: '/user', query: { tab: 'profile' } })
-
router.replace()
:和push
类似,但它会替换当前历史记录(点返回不会回到当前页,而是更前一页),比如支付成功后跳结果页,用replace
避免用户回退又到支付页。 -
router.go(n)
:控制历史记录的前进后退,n
是数字,比如router.go(1)
前进一页,router.go(-1)
后退一页,和浏览器的「前进/后退」按钮逻辑一样。 -
router.back()
/router.forward()
:go(-1)
和go(1)
的快捷写法,更语义化。 -
router.addRoute()
/router.removeRoute()
:动态添加/删除路由规则。权限管理、异步路由的核心!比如后台系统,管理员登录后才加载/admin
路由:// 登录后,给管理员加专属路由 if (user.role === 'admin') { router.addRoute({ path: '/admin', component: () => import('./views/Admin.vue') }) }
组件里怎么“喊”这个大管家?
路由对象是单例,但在不同场景(组件内、组件外)访问方式不一样。
组件内部:用钩子函数
Vue 3的组合式API里,用useRouter()
和useRoute()
:
<template> <button @click="goToAbout">去关于页</button> </template> <script setup> import { useRouter } from 'vue-router' const router = useRouter() // 拿到路由对象 function goToAbout() { router.push('/about') // 跳转 } </script>
Vue 2的选项式API,或者Vue 3里用选项式写法,用this.$router
和this.$route
(前提是Vue实例里注入了路由):
export default { methods: { goToAbout() { this.$router.push('/about') } } }
注意:想拿“当前路由信息”(比如参数、查询参数),用useRoute()
或this.$route
;想“操作路由”(跳转、加路由),用useRouter()
或this.$router
。
组件外部:直接导入实例
如果在Vuex仓库、工具函数、JS文件里操作路由,直接导入创建好的router
实例就行:
// router.js(创建路由的文件) export const router = createRouter({ ... }) // 注意要导出 // utils/auth.js(工具文件) import { router } from '../router.js' // 登录成功后跳转 function loginSuccess() { router.push('/dashboard') }
实战:用Vue Router Object 搞动态路由、权限控制
很多复杂场景(比如权限路由、多租户系统),核心就是动态增删路由 + 导航守卫。
场景1:根据用户权限加载路由(动态路由)
后台系统里,普通用户看不到/admin
页面,管理员登录后才加载这个路由,步骤:
- 先在路由规则里写个“占位符”(可选,也可以完全动态加);
- 登录成功后,用
router.addRoute()
加管理员路由; - 用导航守卫(
router.beforeEach
)拦截未授权访问。
代码示例:
// router.js 初始化时,先不加/admin路由 const routes = [ { path: '/login', component: Login }, { path: '/', component: Home, meta: { requiresAuth: true } } ] const router = createRouter({ ... }) // 全局前置守卫:跳转前检查权限 router.beforeEach((to, from, next) => { // 如果目标页面需要登录,且用户没登录,跳登录页 if (to.meta.requiresAuth && !isLoggedIn()) { next({ name: 'login' }) } else { next() // 放行 } }) // 登录逻辑(比如在Login组件里) function handleLogin() { // 假设登录后拿到用户角色 const user = loginApi() if (user.role === 'admin') { // 动态添加管理员路由 router.addRoute({ path: '/admin', component: () => import('./views/Admin.vue'), meta: { requiresAuth: true } }) } // 跳转到首页 router.push('/') }
场景2:路由元信息(meta)控制页面行为
路由元信息是给路由“贴标签”的,比如标记“是否需要登录”“页面标题”“过渡动画”。
配置路由时加meta
:
{ path: '/profile', component: Profile, meta: { requiresAuth: true, '个人中心', transition: 'fade' // 过渡动画名称 } }
然后在导航守卫里用to.meta
做逻辑:
router.beforeEach((to, from, next) => { // 设置页面标题 document.title = to.meta.title || '默认标题' next() })
或者在组件里根据meta
做过渡动画:
<router-view v-slot="{ Component, route }"> <Transition :name="route.meta.transition || 'slide'"> <component :is="Component" /> </Transition> </router-view>
避坑指南:这些问题90%的人都踩过
路由开发时,有些“玄学”问题其实是对路由对象理解不到位导致的,这里列几个高频坑:
坑1:路由跳转后,组件没更新
比如从/user/1
跳到/user/2
,URL变了但页面数据没刷新。原因是Vue复用了相同组件(路径结构一样,只是参数变了),组件的生命周期没触发。
解决方法:
- 监听路由变化:在组件里用
watch
监听$route
(或useRoute()
)的变化,参数变了就重新请求数据。// 组合式API import { useRoute, watch } from 'vue-router' const route = useRoute() watch(route, (newRoute) => { // newRoute.params.id 变化了,重新请求数据 fetchUser(newRoute.params.id) })
- 给组件加key:让Vue认为是不同组件,强制销毁重建。
<template> <UserComponent :key="$route.params.id" /> </template>
坑2:动态加路由重复了
多次调用router.addRoute()
会导致同一路由被重复添加,页面可能出问题。解决方法是先检查是否已存在:
if (!router.hasRoute('admin')) { // hasRoute 检查路由是否存在(按name判断) router.addRoute({ name: 'admin', path: '/admin', component: Admin }) }
坑3:history模式下刷新页面404
用createWebHistory()
(history模式)时,直接刷新页面,后端如果没配置,会返回404。原因是前端路由走的是HTML5 History API,后端不认识前端的路由路径。
解决:让后端把所有前端路由的请求,都转发到index.html
,比如Nginx配置:
location / { try_files $uri $uri/ /index.html; }
坑4:导航守卫里next()
用错了
导航守卫(比如beforeEach
)里的next()
是控制导航是否继续的函数,必须确保只调用一次!比如异步逻辑里没处理好,就会报错。
错误示例(多次调用next):
router.beforeEach((to, from, next) => { if (to.meta.requiresAuth) { next({ name: 'login' }) // 这里调了next } next() // 又调了next,重复调用会报错! })
正确写法(确保只调一次):
router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !isLoggedIn()) { next({ name: 'login' }) } else { next() // 只在else里调 } })
进阶:路由对象还能玩出啥花样?
除了基础功能,结合Vue生态,路由对象能搞很多高阶玩法:
路由过渡动画的精细化控制
不同页面用不同过渡效果,靠route.meta.transition
动态切换:
<router-view v-slot="{ Component, route }"> <Transition :name="route.meta.transition"> <component :is="Component" /> </Transition> </router-view>
然后在路由配置里指定:
{ path: '/home', component: Home, meta: { transition: 'slide-left' } }, { path: '/about', component: About, meta: { transition: 'slide-right' } }
路由懒加载 + 进度条
结合import()
懒加载和NProgress进度条,路由跳转时显示加载状态:
// 全局路由守卫里加进度条逻辑 import NProgress from 'nprogress' router.beforeEach((to, from, next) => { NProgress.start() // 开始加载 next() }) router.afterEach(() => { NProgress.done() // 加载完成 }) // 路由规则里用懒加载 { path: '/about', component: () => { NProgress.set(0.5) // 加载到一半时设进度 return import('./views/About.vue') } }
多标签页(类似浏览器标签)
模拟多标签页功能,用router.push
配合keep-alive
和标签数组,记录用户打开的页面:
// 存储打开的标签页 const visitedTabs = ref([]) function openTab(path) { if (!visitedTabs.value.includes(path)) { visitedTabs.value.push(path) } router.push(path) } // 模板里循环渲染标签 <template> <div v-for="path in visitedTabs" :key="path"> <button @click="router.push(path)">{{ path }}</button> </div> <router-view v-slot="{ Component }"> <keep-alive> <component :is="Component" /> </keep-alive> </router-view> </template>
掌握Vue Router Object 等于掌控路由命脉
从基础的“是什么”,到核心的“怎么用”,再到实战的“怎么玩出花”,Vue Router Object 贯穿了路由开发的全流程,理解它的属性、方法,结合导航守卫、动态路由、元信息这些工具,不管是简单的页面跳转,还是复杂的权限管理、多端适配,都能游刃有余。
最后再强调个心法:路由对象是“管理者”,它的一切设计都是为了让路由逻辑更集中、更可控,遇到路由问题时,先想“路由对象能提供什么方法/属性”,很多问题自然就有了方向~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。