在前端单页应用(SPA)中,路由是连接用户操作与页面展示的核心桥梁。Vue Router 作为 Vue 官方的路由管理器,提供了丰富的功能和灵活的配置。本文将围绕"路由模式"、"router 与 route 的区别"、"导航守卫的种类"以及"完整的导航解析流程"四个方面,带你深入理解 Vue Router 的工作机制。
一、路由模式:hash 与 history 的实现原理
Vue Router 支持两种主流的路由模式:hash 模式 和 history 模式。它们的底层实现机制不同,决定了使用方式和部署时的差异。
1. hash 模式
hash 模式是基于 URL 中 #
后面的内容变化实现的。浏览器不会将 #
后的部分发送到服务器,因此不会触发页面刷新。
- 监听机制:通过监听
window.onhashchange
事件,捕获 hash 值的变化。 - 优点:
- 兼容性好,支持 IE 及以下版本。
- 部署简单,刷新页面不会 404。
- 缺点:
- URL 不够美观,带有
#
符号。
- URL 不够美观,带有
2. history 模式
history 模式依赖 HTML5 提供的 pushState
和 replaceState
API,可以在不刷新页面的情况下修改 URL。
- 监听机制:通过监听
popstate
事件,捕获浏览器前进/后退操作。 - 优点:
- URL 更干净,没有
#
。
- URL 更干净,没有
- 缺点:
- 需要后端配合,刷新页面或直接访问子路径时,需将所有请求重定向到入口文件(如
index.html
),否则会返回 404。 - 对低版本浏览器支持不佳。
- 需要后端配合,刷新页面或直接访问子路径时,需将所有请求重定向到入口文件(如
二、router 与 route 的区别
在 Vue 组件中,我们常常使用 this.$router
和 this.$route
,但它们代表的含义完全不同:
router
- 是 Vue Router 的实例对象,包含整个路由的配置和控制方法。
- 常用方法:
this.$router.push()
:跳转到指定路由,添加一条历史记录。this.$router.replace()
:替换当前路由,不添加历史记录。this.$router.go(n)
:前进或后退 n 步。
route
- 是当前激活路由的信息对象,包含与当前路径相关的所有信息。
- 常用属性:
this.$route.path
:当前路径,如/user/123
。this.$route.params
:动态路由参数,如{ id: 123 }
。this.$route.query
:查询参数,如?tab=profile
对应{ tab: 'profile' }
。this.$route.name
:当前路由的名称。this.$route.meta
:路由元信息,常用于权限控制。
简言之:router 是"路由器",负责操作;route 是"当前路线",负责提供信息。
三、导航守卫的种类
Vue Router 提供了多种导航守卫,用于在路由跳转前后执行逻辑控制,分为三大类:
1. 全局守卫
作用于整个应用,定义在 router 实例上:
router.beforeEach(to, from, next)
:全局前置守卫,常用于登录验证。router.beforeResolve(to, from, next)
:全局解析守卫,2.5+ 引入,所有组件内守卫和异步路由组件解析完成后触发。router.afterEach(to, from)
:全局后置钩子,不能拦截导航,常用于页面埋点。
2. 路由独享守卫
定义在单个路由配置中,仅对该路由生效:
beforeEnter(to, from, next)
:进入该路由前触发,用法与全局守卫类似。
3. 组件内守卫
定义在 Vue 组件内部,与组件生命周期紧密结合:
beforeRouteEnter(to, from, next)
:组件被激活前调用,此时组件实例尚未创建,无法访问this
。beforeRouteUpdate(to, from, next)
:当前路由改变但组件被复用时调用(如/user/1
→/user/2
)。beforeRouteLeave(to, from, next)
:离开当前路由时调用,可用于提示用户保存未提交的表单。
四、完整的导航解析流程
Vue Router 的导航过程是一个链式调用的过程,每一步都可以中断或继续。以下是完整的流程:
- 导航触发:用户点击
<router-link>
或调用$router.push()
。 - 调用失活组件的
beforeRouteLeave
:如从/user/1
跳转到/about
。 - 调用全局
beforeEach
守卫。 - 调用重用组件的
beforeRouteUpdate
(若组件被复用)。 - 调用路由独享的
beforeEnter
。 - 解析异步组件(若该路由配置了异步组件)。
- 调用激活组件的
beforeRouteEnter
。 - 调用全局
beforeResolve
守卫。 - 导航被确认。
- 调用全局
afterEach
钩子。 - 触发 DOM 更新。
- 执行
beforeRouteEnter
中next
的回调,此时组件实例已创建,可通过回调参数访问。