Code前端首页关于Code前端联系我们

Vue Router 高频面试题都在这了,看完再也不怕面试官提问!

terry 21小时前 阅读数 34 #SEO
文章标签 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 APIpushStatereplaceState),URL 是干净的(http://xxx.com/user),但缺点是需要后端配合:如果用户直接访问 http://xxx.com/user,服务器得配置“ fallback 规则”(比如所有请求都返回 index.html),否则会报 404,优点是 URL 更友好,符合用户习惯。

怎么实现路由的动态匹配(动态路由)?用的时候要注意啥?

动态路由是指 URL 里带可变参数,比如用户详情页 /user/1/user/2,参数 12 是动态的。

配置方式:

在路由规则里,用 参数名 定义动态段,

const routes = [
  { path: '/user/:id', component: User }
]

组件内获取参数:

在 User 组件里,通过 this.$route.params.id 拿到动态参数($route 是当前路由对象)。

注意“路由复用”问题:

如果用户从 /user/1 跳到 /user/2,因为是同一个组件(User)被复用,组件的 createdmounted 等生命周期钩子不会重新执行!这时候如果想根据新的 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 是在组件实例创建之前触发的(因为路由要进入,组件还没渲染),所以此时 thisundefined

解决方法:

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 里的用户信息要同步更新,可以在 beforeRouteUpdatewatch $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>

控制缓存范围:

includeexclude 指定缓存哪些组件(基于组件名):

<keep-alive include="Home,User">
  <router-view></router-view>
</keep-alive>

注意点:

  • 缓存后,组件的 createdmounted 等钩子只执行一次,之后切换路由再回来,不会重新执行,如果要更新数据,得用 activated 钩子(组件被激活时触发):
    activated() {
      this.fetchData() // 每次激活都重新请求数据
    }
  • 如果是路由参数变化导致组件复用(/user/1/user/2),要在 beforeRouteUpdatewatch $route 里处理数据更新,因为 activated 不会触发(组件没被销毁,只是参数变了)。

移动端路由切换时的动画效果咋实现?

给路由切换加动画,核心是用 Vue 的 <transition> 组件包裹 <router-view>,结合 CSS 过渡。

步骤:

  1. <transition> 包裹 <router-view>,定义 name

    <transition name="slide">
      <router-view></router-view>
    </transition>
  2. 写 CSS 过渡样式(以“从右往左滑入”为例):

    .slide-enter-active, .slide-leave-active {
      transition: all 0.3s ease;
    }
    .slide-enter-from {
      transform: translateX(100%);
    }
    .slide-leave-to {
      transform: translateX(-100%);
    }
  3. 进阶:根据跳转方向加不同动画(比如返回时从左往右滑),可以通过判断 fromto 的路径,动态切换 <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前端网发表,如需转载,请注明页面地址。

热门