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

vue-router 基础配置要做哪些事?

terry 3周前 (09-05) 阅读数 51 #Vue
文章标签 router 基础配置

不少刚开始用Vue做项目的同学,一碰到路由配置、跳转、权限控制这些需求,就被vue-router API的各种用法搞晕,这篇文章用问答形式,把vue-router核心API的用法、场景和实战技巧拆明白,从基础配置到进阶玩法一次讲透~

要让vue-router在项目里跑起来,得完成「安装→创建路由实例→配置路由规则→注入Vue」这几步。

先装依赖:Vue2项目用 npm i vue-router@3,Vue3项目用 npm i vue-router@4

然后创建路由实例:

  • Vue2 写法

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Home from './views/Home.vue'
    Vue.use(VueRouter) // 全局注册路由插件
    const routes = [
      { path: '/', component: Home },
      { path: '/about', component: () => import('./views/About.vue') } // 懒加载组件
    ]
    const router = new VueRouter({
      mode: 'history', // 选择history或hash模式(hash模式用'hash')
      routes
    })
    export default router
  • Vue3 写法

    import { createRouter, createWebHistory } from 'vue-router'
    import Home from './views/Home.vue'
    const routes = [
      { path: '/', component: Home },
      { path: '/about', component: () => import('./views/About.vue') }
    ]
    const router = createRouter({
      history: createWebHistory(), // history模式(hash模式用createWebHashHistory)
      routes
    })
    export default router

最后在入口文件(main.js)里注入:Vue2是 new Vue({ router, ... }).$mount('#app');Vue3是 app.use(router).mount('#app')

配置路由规则时,path 是访问路径,component 对应渲染的组件,还能加 name(命名路由,跳转更稳定)、meta(元信息,存权限、标题等自定义数据)等字段。

路由跳转有几种方式?代码咋写?

路由跳转分「声明式」和「编程式」两种,场景不同选不同方式~

声明式:用 <router-link> 组件

在模板里写,适合页面上的导航按钮、菜单等场景,比如跳转到命名路由并传参:

<router-link :to="{ name: 'User', params: { id: 123 }}">去用户页</router-link>

也能传query参数(参数会拼在URL后,如 ?keyword=vue):

<router-link :to="{ path: '/search', query: { keyword: 'vue' }}">搜索Vue</router-link>

编程式:用 router 的方法

在JS里调用,适合按钮点击、逻辑判断后跳转等场景,常见方法有 pushreplacego

  • Vue2 里,组件内通过 this.$router 调用:

    methods: {
      goAbout() {
        this.$router.push('/about') // 直接传路径
        this.$router.push({ name: 'About', params: { tab: 'info' }}) // 命名路由+参数
      }
    }
  • Vue3 里,要用 useRouter 钩子拿到router实例:

    import { useRouter } from 'vue-router'
    setup() {
      const router = useRouter()
      const goUser = () => {
        router.push({ name: 'User', params: { id: '456' }})
      }
      return { goUser }
    }

几个方法区别:

  • push:新增一条历史记录,点击返回能回到上一页;
  • replace:替换当前历史记录,点击返回不会回到当前页;
  • go:类似 history.go(n)router.go(-1) 是返回上一页。

动态路由参数咋处理?匹配和传参要注意啥?

动态路由用来匹配「路径里带变量」的场景(比如用户页 /user/1/user/2 共用一个User组件)。

配置动态路由

在路由规则里加动态段(以 开头),

{ path: '/user/:id', name: 'User', component: User }

这里的 :id 就是动态参数,页面刷新后参数还在(因为参数在URL里)。

组件内获取参数

  • Vue2 里,用 this.$route.params.id(注意是 $route 不是 $router$route 是当前路由信息对象);
  • Vue3 里,用 useRoute 钩子:
    import { useRoute } from 'vue-router'
    setup() {
      const route = useRoute()
      console.log(route.params.id) // 拿到动态参数
    }

注意!参数变化时组件不刷新

当从 /user/1 跳到 /user/2,User组件会复用(性能优化),但组件的生命周期钩子(比如created)不会再执行,这时候要监听参数变化

  • watch 监听 $route(Vue2)或 route(Vue3):

    // Vue3 示例
    watch(route, (newRoute, oldRoute) => {
      console.log('参数变了', newRoute.params.id)
      // 这里做数据重新请求等操作
    })
  • 用组件内守卫 beforeRouteUpdate(Vue2/Vue3都支持):

    beforeRouteUpdate(to, from, next) {
      console.log('路由更新,新参数是', to.params.id)
      next() // Vue2需要调用next,Vue3可省略或return
    }

嵌套路由怎么配置和使用?

嵌套路由用来实现「父组件里嵌套子组件」的场景(比如后台管理系统,左侧菜单栏是父组件,右侧内容区根据路由切换子组件)。

配置嵌套路由

在父路由的 children 数组里写子路由规则:

{
  path: '/dashboard', // 父路由路径
  component: Dashboard, // 父组件
  children: [
    { path: '', component: DashboardHome }, // 默认子路由,访问/dashboard时显示
    { path: 'settings', component: DashboardSettings }, // 访问/dashboard/settings时显示
    { path: 'profile', component: DashboardProfile }
  ]
}

父组件里放 <router-view>

父组件(比如Dashboard.vue)的模板里,得有 <router-view> 来渲染子组件:

<template>
  <div class="dashboard">
    <aside>左侧菜单</aside>
    <main>
      <router-view></router-view> <!-- 子组件渲染在这里 -->
    </main>
  </div>
</template>

这样,访问 /dashboard/settings 时,Dashboard组件渲染,同时Settings子组件渲染到父组件的 <router-view> 位置。

路由守卫有哪些?分别在啥场景用?

路由守卫是「路由跳转前后的钩子函数」,用来做权限验证、数据加载、页面跳转拦截这些事,分三大类:

全局守卫(作用于所有路由)

  • router.beforeEach:路由跳转前触发(全局前置守卫),常用作权限控制
    例子:判断用户是否登录,没登录跳登录页:

    router.beforeEach((to, from, next) => {
      if (to.meta.requiresAuth && !isLogin()) {
        next({ name: 'Login' }) // 跳登录页
      } else {
        next() // 放行
      }
    })

    Vue3里可以不用next,直接return目标路由或false

    router.beforeEach((to, from) => {
      if (to.meta.requiresAuth && !isLogin()) {
        return { name: 'Login' }
      }
    })
  • router.beforeResolve:导航确认前触发(所有组件内守卫和路由独享守卫执行完后),少用,了解即可。

  • router.afterEach:路由跳转完成后触发(全局后置守卫),常用作设置页面标题

    router.afterEach((to) => {
      document.title = to.meta.title || '默认标题'
    })

路由独享守卫(作用于单个路由)

在路由规则里写 beforeEnter,比如某个页面需要单独验证权限

{
  path: '/order',
  component: Order,
  beforeEnter: (to, from, next) => {
    if (hasOrderPermission()) {
      next()
    } else {
      next({ name: 'Forbidden' })
    }
  }
}

组件内守卫(作用于组件内)

  • beforeRouteEnter:进入组件前触发(组件实例还没创建,所以拿不到 this),适合提前请求数据

    beforeRouteEnter(to, from, next) {
      fetchData().then(data => {
        next(vm => { // vm是组件实例,进入后把数据给vm
          vm.data = data
        })
      })
    }
  • beforeRouteUpdate:路由参数变化时触发(组件复用场景,比如/user/1/user/2),前面讲动态路由时提过。

  • beforeRouteLeave:离开组件前触发,常用作阻止误操作(比如表单没保存):

    beforeRouteLeave(to, from, next) {
      if (this.formDirty) {
        if (window.confirm('表单没保存,确定离开?')) {
          next()
        } else {
          next(false) // 取消离开
        }
      } else {
        next()
      }
    }

路由懒加载怎么实现?有啥好处?

路由懒加载是「把组件打包成单独的JS文件,访问时再加载」,能减小首屏bundle体积,加快首屏加载速度

实现方式

用 ES6 的 import() 函数代替直接 import 组件。

{
  path: '/about',
  component: () => import('./views/About.vue') // 懒加载,打包时生成单独chunk
}

对比「非懒加载」:

import About from './views/About.vue' // 会把About打包进主JS,首屏加载时一起加载
{ path: '/about', component: About }

好处

  • 首屏加载更快:只加载首页必要代码,其他页面按需加载;
  • 代码分割更细:不同路由组件分开打包,避免单个JS文件过大;
  • 缓存友好:用户访问过的页面,下次再访问会从缓存取。

路由元信息(meta)有啥用?怎么玩?

路由元信息是给路由规则加 meta 字段,存自定义数据(比如权限、页面标题、是否需要缓存组件)。

配置meta

在路由规则里加:

{
  path: '/admin',
  component: Admin,
  meta: { 
    requiresAuth: true, // 需要登录 '管理后台', // 页面标题
    keepAlive: true // 是否缓存组件
  }
}

读取meta

  • 全局守卫里读:router.beforeEach 里判断 to.meta.requiresAuth(前面权限验证的例子);
  • 组件内读:用 $route.meta(Vue2)或 useRoute().meta(Vue3);
  • 全局后置守卫改标题:router.afterEach 里用 to.meta.title(前面改页面标题的例子)。

还能结合 <keep-alive> 实现组件缓存:根据 meta.keepAlive 决定是否缓存组件~

404页面咋配置?路由优先级要注意啥?

404页面用来处理「用户访问不存在的路径」的情况,配置时要注意路由匹配的优先级

配置通配符路由

/:pathMatch(.*)* 匹配所有未定义的路径:

{
  path: '/:pathMatch(.*)*', // 匹配所有路径
  name: 'NotFound',
  component: () => import('./views/NotFound.vue')
}

路由优先级

Vue-router 是「从上到下匹配路由规则,一旦匹配到就渲染」,所以404路由要放在routes数组的最后面,否则前面的路由还没匹配,就被404截胡了。

比如正确顺序:

const routes = [
  { path: '/', component: Home },
  { path: '/user/:id', component: User },
  { path: '/:pathMatch(.*)*', component: NotFound } // 最后放404
]

Vue2和Vue3的vue-router API有啥区别?

Vue2用 vue-router@3.x,Vue3用 vue-router@4.x,核心功能一样,但API和实现有不少变化:

创建路由的方式

  • Vue2:new VueRouter({ mode: 'history', routes })
  • Vue3:createRouter({ history: createWebHistory(), routes })(history模式),hash模式用 createWebHashHistory

组合式API(Vue3新增)

Vue3里可以用 useRouteruseRoute 钩子,代替Vue2里的 this.$routerthis.$route

// Vue3 setup 里
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()

响应式与守卫写法

Vue3中,route 是响应式对象,用 watch 监听更方便;路由守卫里的 next 可选,推荐用return控制导航。

模式配置

Vue2的 mode: 'history' 对应Vue3的 createWebHistory()mode: 'hash' 对应 createWebHashHistory()

路由跳转时的query和params有啥不同?

传参时选query还是params,得看「参数是否要留在url里」「刷新后是否保留」这些需求~

query参数

  • 特点:拼在url的查询字符串里(/search?keyword=vue);
  • 刷新后还在:因为参数在url里;
  • 传参方式:{ path: '/search', query: { keyword: 'vue' }}router.push({ path: '/search', query: { keyword: 'vue' }})
  • 取值:$route.query.keyword(Vue2)或 useRoute().query.keyword(Vue3)。

params参数

  • 特点:有两种场景——
    ① 配合动态路由(/user/:id),参数在url里(/user/123),刷新后保留;
    ② 命名路由传参({ name: 'User', params: { id: 123 }}),参数不在url里,刷新后丢失(除非配了动态路由);
  • 传参方式:必须用「命名路由」,不能直接传path(因为path里没动态段的话,params会被忽略);
  • 取值:$route.params.id(Vue2)或 useRoute().params.id(Vue3)。

怎么选?

  • 想让参数刷新后还在,且愿意暴露在url里→用query;
  • 想让参数在url里(如用户ID)→配动态路由+params;
  • 临时传参、刷新后不需要保留→用命名路由的params(但要注意刷新丢失问题)。

看完这些问题,你对vue-router API的核心用法应该清晰多了~ 实际项目里,把「路由配置+跳转+守卫+元信息」这些知识点结合起来,就能搞定权限控制、页面跳转、组件复用这些常见需求,要是还有细节没吃透,建议去官方文档里针对性查案例,多写几个小demo练手,用熟了自然就顺手啦~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门