Vue Router 高频面试题都在这了,看完再也不怕面试官提问!
Vue Router 是干啥的?和传统页面跳转有啥区别?
Vue Router 是 Vue 生态里专门管理单页应用(SPA)路由的工具,你可以把它理解成“组件导航员”——负责在不同组件之间切换,同时让 URL 变化能对应到不同页面状态,而且整个过程页面不会刷新。
传统多页面应用(PHP 渲染的网站)是“页面级跳转”:点个链接,浏览器会请求新的 HTML 页面,整个页面重新加载,体验上会有闪烁,资源也得重新拉取,但 SPA 是“组件级切换”,整个应用只有一个 HTML 文件,路由切换时只是替换页面里的组件,配合 Ajax 异步拿数据,体验更流畅,加载也更高效。
Vue Router 有哪几种路由模式?区别是啥?
Vue Router 主要有 hash 模式 和 history 模式 两种,核心差异在 URL 表现和底层原理:
-
Hash 模式:URL 里带 (
http://xxx.com/#/user)。 后面的内容是“锚点”,不会传给服务器,所以刷新页面时,服务器只收到http://xxx.com/,前端再解析 后的路由,好处是兼容性好(老浏览器也支持),不用后端配合;缺点是 URL 有个 ,不太美观。 -
History 模式:用 HTML5 的
History API(pushState、replaceState),URL 是干净的(http://xxx.com/user),但缺点是需要后端配合:如果用户直接访问http://xxx.com/user,服务器得配置“ fallback 规则”(比如所有请求都返回 index.html),否则会报 404,优点是 URL 更友好,符合用户习惯。
怎么实现路由的动态匹配(动态路由)?用的时候要注意啥?
动态路由是指 URL 里带可变参数,比如用户详情页 /user/1、/user/2,参数 1、2 是动态的。
配置方式:
在路由规则里,用 参数名 定义动态段,
const routes = [
{ path: '/user/:id', component: User }
]
组件内获取参数:
在 User 组件里,通过 this.$route.params.id 拿到动态参数($route 是当前路由对象)。
注意“路由复用”问题:
如果用户从 /user/1 跳到 /user/2,因为是同一个组件(User)被复用,组件的 created、mounted 等生命周期钩子不会重新执行!这时候如果想根据新的 id 重新请求数据,得用两种方法:
- 监听
$route的变化:watch: { '$route' (to, from) { // to.params.id 是新参数,发请求拿数据 } } - 用组件内守卫
beforeRouteUpdate:beforeRouteUpdate(to, from, next) { // 拿到 to.params.id 发请求,再 next() next() }
路由传参有哪几种方式?各自优缺点是啥?
常见的路由传参方式有 params 传参、query 传参、props 传参 三种,适用场景不同:
params 传参(动态路由参数)
- 配置:路由规则写
path: '/user/:id',跳转时用this.$router.push('/user/123')。 - 取值:
this.$route.params.id。 - 优缺点:参数“藏”在 URL 路径里,URL 更简洁;但如果路由规则没定义
id,刷新页面后参数会丢失(因为不在 URL 里存着)。
query 传参(查询参数)
- 配置:不需要改路由规则,跳转时用
this.$router.push({ path: '/user', query: { name: '小明' } }),URL 变成'/user?name=小明'。 - 取值:
this.$route.query.name。 - 优缺点:参数在 URL 里明明白白,刷新页面不会丢;但 URL 会变长,也可能暴露敏感信息。
props 传参(把路由参数转成组件 props)
- 配置:路由规则里开启
props: true,或者写函数返回 props:{ path: '/user/:id', component: User, props: true } - 组件里:直接定义
props: ['id'],用this.id接收,不用再写$route.params.id。 - 优缺点:让组件摆脱对
$route的依赖,更易复用、测试;但需要额外配置路由,适合参数和组件强关联的场景。
路由懒加载咋实现?有啥好处?
路由懒加载是为了优化首屏加载速度——把每个路由对应的组件,打包成单独的 JS chunk,只有用户访问到该路由时才加载。
实现方式:
用 ES6 的 import() 语法(动态导入),替换原来的静态 import:
const routes = [
{
path: '/about',
component: () => import('./views/About.vue') // 懒加载!
}
]
好处:
- 首屏不需要加载所有页面的代码,初始 JS 包体积变小,加载更快。
- 访问不同路由时再加载对应组件,按需加载,节省流量和性能。
- 代码拆分更细,利于浏览器缓存(About 组件更新,只重新打包 About 的 chunk)。
路由嵌套该怎么配置?实际项目里啥场景会用?
路由嵌套是指父路由里包含子路由,对应页面结构也是“父组件里嵌套子组件”。
配置方式:
在父路由的 children 数组里写子路由规则,父组件中要有 <router-view> 来渲染子组件:
const routes = [
{
path: '/dashboard',
component: Dashboard, // 父组件
children: [
{ path: '', component: Home }, // 子路由,默认显示 Home
{ path: 'settings', component: Settings } // 子路由:/dashboard/settings
]
}
]
实际场景:
最典型的是后台管理系统。/dashboard 是布局页(包含侧边栏、顶栏),点击侧边栏的“首页”“设置”“用户管理”,其实是切换 /dashboard 下的子路由,这样布局组件只渲染一次,子组件按需切换,结构清晰又复用。
导航守卫有哪些?执行顺序是咋样的?
导航守卫是“路由跳转过程中的钩子函数”,能在跳转前、跳转后做权限验证、数据加载等操作,分三类:全局守卫、路由独享守卫、组件内守卫。
全局守卫(作用于整个路由系统)
router.beforeEach(to, from, next):路由跳转前触发(最常用,比如权限验证)。router.beforeResolve(to, from, next):所有组件内守卫和路由独享守卫执行完后,跳转前触发。router.afterEach(to, from):路由跳转完成后触发(没有 next,只能做统计、埋点)。
路由独享守卫(只作用于某个路由)
beforeEnter(to, from, next):在路由规则里写,{ path: '/user', component: User, beforeEnter: (to, from, next) => { ... } }
组件内守卫(在组件里写的钩子)
beforeRouteEnter(to, from, next):进入该组件对应的路由前触发(组件实例还没创建,this是 undefined)。beforeRouteUpdate(to, from, next):路由参数变化,但组件复用(/user/1→/user/2)时触发。beforeRouteLeave(to, from, next):离开该组件对应的路由前触发(比如判断表单是否保存)。
执行顺序(关键!):
当从路由 A 跳转到路由 B 时,顺序是:
全局 beforeEach → 路由 B 的 beforeEnter → 组件 B 的 beforeRouteEnter → 全局 beforeResolve → 组件 B 渲染 → 全局 afterEach
全局前置守卫router.beforeEach 咋用?常见应用场景是啥?
router.beforeEach 是“全局路由门卫”,每次路由跳转前都会触发,能决定是否放行、跳转到哪。
基本用法:
router.beforeEach((to, from, next) => {
// to:要跳转到的目标路由对象
// from:当前离开的路由对象
// next:放行函数,必须调用!
if (to.path === '/login') {
next() // 放行到登录页
} else {
// 假设用 localStorage 存登录状态
if (localStorage.getItem('token')) {
next() // 已登录,放行
} else {
next('/login') // 未登录,跳登录页
}
}
})
常见场景:
- 权限控制:比如后台页面必须登录才能进,未登录就跳登录页(如上例)。
- 设置页面标题:路由元信息(
to.meta.title)可以配置标题,在这里用document.title = to.meta.title。 - 加载状态控制:跳转时显示加载动画,
next后隐藏动画。
组件内守卫beforeRouteEnter 为啥拿不到this?咋解决?
beforeRouteEnter 是在组件实例创建之前触发的(因为路由要进入,组件还没渲染),所以此时 this 是 undefined。
解决方法:
给 next 传一个回调函数,组件实例创建后,回调里的 vm 就是组件实例:
beforeRouteEnter(to, from, next) {
next(vm => {
// vm this!可以访问组件数据、方法
vm.getData() // 调用组件内的 getData 方法
})
}
路由出错(比如404页面)咋处理?
要做“兜底路由”,捕获所有未匹配的路径,跳转到404页面。
配置通配符路由:
在路由规则的最后面(因为路由匹配是“从上到下”,通配符 要放最后)加:
const routes = [
// 其他路由...
{ path: '/:pathMatch(.*)*', component: NotFound }
]
这里 pathMatch(.*)* 是 Vue Router 4 的写法(兼容任意层级的路径,/a/b/c),Vue Router 3 用 即可。
处理异步组件加载错误:
如果路由用了懒加载,加载时可能报错(比如网络问题),可以给 import() 加错误捕获:
component: () => import('./views/NotFound.vue').catch(err => {
// 跳转到默认错误页,或提示用户
return { component: ErrorPage }
})
Vue Router 和 Vuex 咋配合使用?
Vuex 管“全局状态”,Vue Router 管“页面导航”,两者常配合处理权限、导航状态等问题。
权限控制(结合 beforeEach)
用户登录状态存在 Vuex 的 store.state.user 里,全局守卫判断是否登录:
router.beforeEach((to, from, next) => {
const isLogin = store.state.user.isLogin
if (to.meta.requiresAuth && !isLogin) {
next('/login')
} else {
next()
}
})
同步路由状态到 Vuex
比如面包屑、当前激活菜单,这些和路由强相关的状态,可以在路由跳转后,把 to 的信息存到 Vuex:
router.afterEach((to, from) => {
store.commit('SET_BREADCRUMB', to.meta.breadcrumb)
})
路由参数变化时更新 Vuex
如果路由参数变了(/user/1 → /user/2),Vuex 里的用户信息要同步更新,可以在 beforeRouteUpdate 或 watch $route 里触发 Vuex 的 action:
watch: {
'$route' (to) {
this.$store.dispatch('fetchUser', to.params.id)
}
}
路由跳转有哪几种方式?区别是啥?
路由跳转分声明式和编程式两种,适用场景不同:
声明式导航()
在模板里用 <router-link> 组件,本质是生成 <a> 标签:
<router-link to="/user">去用户页</router-link>
to属性:可以是字符串路径,也可以是对象(to="{ path: '/user', query: { name: 'xxx' } }")。- 激活样式:默认匹配到当前路由时,会加
router-link-active类,可自定义active-class。
编程式导航(this.$router 方法)
在 JS 里用 this.$router 的方法跳转,常用的有:
push:添加新的历史记录(比如从/home跳/user,可以回退到/home)。replace:替换当前历史记录(回退时跳过当前页)。go:前进/后退若干步(this.$router.go(-1)回退上一页)。
区别:
- 声明式适合模板里的跳转(比如导航栏、菜单),代码简洁;
- 编程式适合逻辑里的跳转(比如登录成功后跳首页,点击按钮触发的跳转)。
路由的keep-alive 和 Vue Router 结合咋用?要注意啥?
<keep-alive> 是 Vue 的内置组件,能缓存组件实例,避免重复创建/销毁,和路由结合时,要包裹 <router-view>:
基本用法:
<keep-alive> <router-view></router-view> </keep-alive>
控制缓存范围:
用 include 或 exclude 指定缓存哪些组件(基于组件名):
<keep-alive include="Home,User"> <router-view></router-view> </keep-alive>
注意点:
- 缓存后,组件的
created、mounted等钩子只执行一次,之后切换路由再回来,不会重新执行,如果要更新数据,得用activated钩子(组件被激活时触发):activated() { this.fetchData() // 每次激活都重新请求数据 } - 如果是路由参数变化导致组件复用(
/user/1→/user/2),要在beforeRouteUpdate或watch $route里处理数据更新,因为activated不会触发(组件没被销毁,只是参数变了)。
移动端路由切换时的动画效果咋实现?
给路由切换加动画,核心是用 Vue 的 <transition> 组件包裹 <router-view>,结合 CSS 过渡。
步骤:
-
用
<transition>包裹<router-view>,定义name:<transition name="slide"> <router-view></router-view> </transition>
-
写 CSS 过渡样式(以“从右往左滑入”为例):
.slide-enter-active, .slide-leave-active { transition: all 0.3s ease; } .slide-enter-from { transform: translateX(100%); } .slide-leave-to { transform: translateX(-100%); } -
进阶:根据跳转方向加不同动画(比如返回时从左往右滑),可以通过判断
from和to的路径,动态切换<transition>的name:<transition :name="transitionName"> <router-view></router-view> </transition>
// 路由守卫里判断方向,设置 transitionName router.beforeEach((to, from, next) => { if (from.path === '/home' && to.path === '/user') { store.commit('SET_TRANSITION_NAME', 'slide-left') } else { store.commit('SET_TRANSITION_NAME', 'slide-right') } next() })
Vue Router 3 和 4 版本有啥主要区别?
Vue Router 3 对应 Vue 2,Vue Router
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



