Vue-Router 详解

475 阅读5分钟

一、Vue-Router基本使用

1.1 安装

  • npm install vue-router

1.2 使用

  1. 创建路由需要映射的组件(打算显示的页面)

  2. 通过createRouter创建路由对象,并且传入routes和history模式

    • 配置路由映射: 组件和路径映射关系的routes数组

    • 创建基于hash或者history的模式

    import { createRouter, createWebHashHistory } from 'vue-router'
    
    import Home from '../views/Home.vue';
    import About from "../views/About.vue";
    
    const router = createRouter({
      // 哈希模式
      history: createWebHashHistory(),
      routes: [
        { path: '/home', component: Home },
        { path: '/about', component: About }
      ]
    })
    
    export default router
    
  3. 使用app注册路由对象(use方法)

    import { createApp } from 'vue'
    import router from './router'
    import App from './App.vue'
    
    createApp(App).use(router).mount('#app')
    
  4. 路由使用: 通过<router-link><router-view>

    <div class="app">
      <div class="nav">
        <router-link to="/home">首页</router-link>
        <router-link to="/about">关于</router-link>
      </div>
      <router-view></router-view>
    </div>
    

二、Vue-Router基础

2.1 默认路径

  • redirect重定向
    • { path: '/', redirect: '/home' }

2.2 history模式

  • createWebHashHistory() 哈希模式
  • createWebHistory() history模式

2.3 router-link其他属性

  • to
    • 跳转的路径,可以是字符串或者一个对象
    • <router-link :to="{ path: '/home' }" replace>首页</router-link>
  • replace
    • 跳转替换不能够返回
  • active-class
    • 设置激活a元素后应用的class,默认是router-link-active
  • exact-active-class
    • 链接精准激活时,应用于渲染的 <a> 的 class,默认是router-link-exact-active

2.4 路由懒加载-分包处理

  • 当打包构建应用时,JavaScript 包会变得非常大,影响页面加载:

    • 如果能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效

    • 也可以提高首屏的渲染效率

  • Vue Router默认就支持动态来导入组件:

    • 这是因为component可以传入一个组件,也可以接收一个函数,该函数 需要放回一个Promise

    • 而import函数就是返回一个Promise

    // 路由的懒加载
    // webpack打包分包会使用下面的名字开头
    const Home = () => import(/* webpackChunkName: 'home' */'../views/Home.vue')
    const About = () => import(/* webpackChunkName: 'about' */'../views/About.vue')
    

2.5 其他属性

  • name:路由记录独一无二的名称

  • meta:自定义的数据

    { 
      name: 'home',
      path: '/home', 
      component: () => import('../views/Home.vue'),
      meta: {
        title: '首页',
        auth: true
      }
    },
    

三、Vue-Router进阶

3.1 动态路由使用

  • path: /user/:id
  • 获取动态路由的值
    • 在template中,直接通过 $route.params获取值;

    • 在created中,通过 this.$route.params获取值;

    • 在setup中,使用 vue-router库给我们提供的一个hook useRoute

      • 该Hook会返回一个Route对象,对象中保存着当前路由相关的值
      import { useRoute } from 'vue-router'
      
      const route = useRoute()
      console.log(route.params.id)
      

3.2 NotFound页面匹配

  • path: /:pathMatch(.*)*
  • 对于没有匹配到的路由,通常会匹配到固定的某个页面(比如404或NotFound)

    • 在错误页面中,可以编写一个动态路由用于匹配所有的页面
    {
      path: '/:pathMatch(.*)*', 
      component: () => import('../views/NotFound.vue')
    },
    
  • 可以通过 $route.params.pathMatch 获取到传入的参数

    • /:pathMatch(.*)/:pathMatch(.*)*的区别在于$route.params.pathMatch解析的时候是否解析

    image.png

3.3 路由的嵌套使用

  1. 在一层路由中添加 children属性:
    children: [
        {
          path: '/home',
          redirect: '/home/recommend'
        },
        {
          path: 'recommend', // /home/recommend
          component: () => import('../views/HomeRecommend.vue')
        },
        {
          path: 'ranking', // /home/ranking
          component: () => import('../views/HomeRanking.vue')
        }
      ]
    
  2. 在Home组件中添加 <router-view>
  3. 路径跳转 <router-link>

3.5 编程式导航

3.5.1 跳转的方式

  • push(路径)

  • push({ path/query })

  • replace()

    import { useRouter } from 'vue-router'
    
    const router = useRouter()
    function jumpToHome() {
      // router.push('/home')
      router.push({
        // name: 'home'
        path: '/home'
      })
    }
    
    function jumpToAbout() {
      // router.push('/about')
      router.push({
        path: '/about',
        query: {
          type: 'common',
          id: '14704170413432'
        }
      })
    }
    

    image.png

3.5.2 页面的前进与后退

  • back()
    • 相当于 router.go(-1)
  • forward()
    • 相当于 router.go(1)
  • go(number)

四、Vue-Router高级

4.1 动态管理路由

4.1.1 什么情况下需要动态管理路由

  • 后台管理系统:根据不同的角色生成不同的菜单
    • 方案一:对应的菜单路由注册,路由守卫拦截
    • 方案二:路由动态注册

4.1.2 动态添加路由

  • router.addRoute({})

  • router.addRoute("name", {})

    // 一级路由
    router.addRoute({
      path: '/admin',
      component: () => import('../views/Admin.vue')
    })
    
    // 添加二级路由
    router.addRoute('home', {
      path: 'vip',
      component: () => import('../views/HomeVip.vue')
    })
    

4.1.3 管理路由别的方法

  • 移除路由有以下三种方式:

    • 方式一:添加一个name相同的路由
    • 方式二:通过removeRoute方法,传入路由的名称
    • 方式三:通过addRoute方法的返回值回调
    // 方式1
    router.addRoute({ path: '/about', name: 'about', component: About })
    // 这将会删除之前已经添加的路由,因为他们具有相同的名字且名字必须是唯一的
    router.addRoute({ path: '/other', name: 'about', component: Other })
    
    // 方式2
    router.addRoute({ path: '/about', name: 'about', component: About })
    // 删除路由
    router.removeRoute('about')
    
    // 方式3
    const removeRoute = router.addRoute(routeRecord)
    removeRoute() // 如果路由存在的话删除路由
    
  • router.getRoutes()

    • 获取一个包含所有路由记录的数组
  • router.hasRoute()

    • 检查路由是否存在

4.2 路由导航守卫

4.2.1 beforeEach

  • vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航

  • 全局的前置守卫beforeEach是在导航触发时会被回调的:

    • 两个参数:

      • to:即将进入的路由Route对象

      • from:即将离开的路由Route对象

    • 返回值:

      • false:取消当前导航

      • 不返回或者undefined:进行默认导航

      • 返回一个路由地址

      • 可以是一个string类型的路径

      • 可以是一个对象,对象中包含path、query、params等信息

    • 可选的第三个参数:next(不推荐使用)

      • 在Vue2中通过next函数来决定如何进行跳转的

      • 在Vue3中通过返回值来控制的,不再推荐使用next函数,这是因为开发中很容易调用多次next

  • 应用场景:

    • 跳转订单时, 判断用户是否登录
    • 没有登录:
      • 调到登录页面
      • 进行登录的操作
      • 保存了token
    • 登录成功:
      • 跳到order页面
    // 进行任何的路由跳转之前,传入到beforeEach中的函数都会被回调
    router.beforeEach((to, from) => {
      // 进入所有页面都跳转登录页面
      // if(to.path !== '/login') {
      //   return '/login'
      // }
    
      const token = localStorage.getItem('token')
      if(to.path === '/order' && !token) {
        return '/login'
      }
      // console.log(to, from)
    })
    

4.2.2 路由导航的流程解析

  • Vue-Router还提供了很多的其他守卫函数,目的都是在某一个时刻给予回调,可以更好的控制程序的流程或者功能:

  • 完整的导航解析流程:

    • 导航被触发。

    • 在失活的组件里调用 beforeRouteLeave 守卫。

    • 调用全局的 beforeEach 守卫。

    • 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。

    • 在路由配置里调用 beforeEnter

    • 解析异步路由组件。

    • 在被激活的组件里调用 beforeRouteEnter

    • 调用全局的 beforeResolve 守卫(2.5+)。

    • 导航被确认。

    • 调用全局的 afterEach 钩子。

    • 触发 DOM 更新。

    • 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。