Flud+
18.7MB · 2026-03-23
在传统多页应用(MPA)中,每次跳转都需要向服务器请求新页面,导致资源重复加载、体验割裂。 **前端路由(SPA)**的核心在于: URL 变化,动态渲染组件,不刷新页面。
window.onhashchange,URL 带 #,兼容性好但 SEO 较差。history.pushState/replaceState,URL 美观,但需后端配合配置(避免 404)。它是 Vue 官方的路由管理器,与 Vue 核心深度集成。
$router 实例。相比 Vue Router 3,v4 版本为了适配 Vue 3 进行了重构,以下是面试官最爱问的变更点:
在 Vue 3 中,我们不再依赖 this.$router 或 this.$route,而是使用钩子函数。
import { useRouter, useRoute } from 'vue-router'
export default {
setup() {
const router = useRouter() // 获取路由实例,用于跳转
const route = useRoute() // 获取当前路由信息(响应式)
// 路由变化
watch(() => route.params.id, (newId) => {
console.log('ID changed:', newId)
})
const goHome = () => {
router.push('/')
}
return { goHome }
}
}
面试追问:useRoute 返回的对象是响应式的吗?
答案:是的,useRoute 返回的是一个响应式对象,其属性(如 params, query)会随 URL 变化而更新,因此可以直接在 watch 或模板中使用。
* 通配符,改用 pathMatchVue Router 4 移除了 * 作为通配符的写法,改为更明确的 :pathMatch(.*)。
// Vue Router 3
{ path: '*', component: NotFound }
// Vue Router 4
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }
原因:为了更符合正则表达式的直观性,并解决某些边缘情况下的匹配歧义。
Vue Router 4 完全用 TypeScript 重写,提供了强大的类型推导。定义路由时即可自动推断 params 和 query 的类型,减少运行时错误。
这是中高级面试的重灾区,通常要求手写一个基于 RBAC(角色访问控制)的动态路由方案。
beforeEach: 最常用,用于登录校验、权限判断。beforeResolve: 所有组件内守卫和异步路由组件解析完成后触发。afterEach: 后置守卫,常用于修改文档标题、统计上报。beforeEnter: 直接在路由配置中定义。onBeforeRouteUpdate: 组件复用时的处理(如 /user/1 跳到 /user/2)。onBeforeRouteLeave: 离开组件前(如表单未保存提示)。beforeRouteEnter 在 Composition API 中无法直接访问 this,通常用 onBeforeRouteUpdate 替代或在 setup 外处理。场景:不同角色的用户登录后,看到的侧边栏菜单不同,且只能访问授权路由。
核心步骤:
router.addRoute() 将过滤后的路由添加到实例中。// 伪代码示例
router.beforeEach(async (to, from, next) => {
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
next({ path: '/' })
} else {
// 判断是否已获取过用户信息/动态路由
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
// 1. 获取用户信息
const { roles } = await store.dispatch('user/getInfo')
// 2. 生成可访问路由表
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// 3. 动态添加路由
accessRoutes.forEach(route => {
router.addRoute(route)
})
// 4. 确保添加完成后再跳转,否则可能 404
next({ ...to, replace: true })
} catch (error) {
// 重置 token 并跳转登录页
await store.dispatch('user/resetToken')
next(`/login?redirect=${to.path}`)
}
}
}
} else {
// 无 Token 处理
next(`/login?redirect=${to.path}`)
}
})
面试坑点:
next(),路由器可能还没解析完新路由,导致 404。必须使用 next({ ...to, replace: true }) 重新触发一次导航。router.removeRoute() 或重置路由实例,防止权限残留。不要一次性加载所有页面组件,利用 import() 实现按需加载。
// 推荐写法
const routes = [
{
path: '/about',
component: () => import('../views/About.vue')
}
]
进阶:结合 Webpack 的 magic comments 进行分组打包,将相关页面打到同一个 chunk 中,减少 HTTP 请求数。
component: () => import(/* webpackChunkName: "user" */ '../views/User/List.vue')
通过 scrollBehavior 定制页面跳转时的滚动位置(如:返回列表页保留滚动位置,进入详情页滚动到顶部)。
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition // 浏览器前进后退时恢复位置
} else {
return { top: 0 } // 新页面跳转到顶部
}
}
})
setup 中直接解构 useRoute() 的属性:这会丢失响应性。
const { params } = useRoute()const route = useRoute(); const id = computed(() => route.params.id)v-if 和 router-link 组合:如果 router-link 被 v-if 包裹且条件为假,可能导致某些事件失效或样式问题,建议用 hidden 样式控制显示。Q: Vue Router 的 Hash 模式和 History 模式有什么区别?生产环境用 History 模式需要注意什么?
hashchange vs pushState)、SEO 影响。History 模式需后端配置 Nginx/Apache,将所有 404 请求重定向到 index.html。Q: 如何实现两个嵌套路由组件之间的通信?
props/emit;跨层级可用 provide/inject 或 Pinia/Vuex;或者通过 $parent / $children (不推荐)。Q: 路由参数 params 和 query 的区别?刷新页面后会丢失吗?
params 是路径的一部分 (/user/1),刷新不丢失(前提是路由配置了动态段);query 是查询字符串 (?id=1),刷新不丢失。若 params 未在路由配置中定义,刷新后会丢失。Q: 讲一下你项目中是如何做权限管理的?
addRoute、全局守卫拦截、菜单动态生成、登出清理路由。Q: Vue Router 4 中如何路由变化?
watch($route);在 Composition API 用 watch(() => route.path) 或 watch(() => route.params.id)。掌握 Vue Router 不仅仅是记住 API,更重要的是理解其**“状态驱动视图”的设计思想,以及如何利用它构建安全、高性能、可维护**的单页应用架构。在 2026 年的面试中,能够结合业务场景(如权限、埋点、性能优化)阐述路由设计的候选人,必将脱颖而出。