Vue3 VueRouter 使用和原代码解析

132 min read

基本使用

https://router.vuejs.org/zh/introduction.html

// 安装及配置
npm install vue-router@4
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/AboutView.vue')
    }
  ]
})

export default router
// 入口文件
import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(router)

app.mount('#app')

createRouter的路由模式

history模式对应createWebHistory()方法

hash模式对应createWebHashHistory()方法

createRouter的路由懒加载

vue提供的一个方法defineAsyncComponent

createRouter的注册使用路由

// src/main.js

import { createApp } from 'vue'
import router from './router'
import store from './store'
import App from './App.vue'

// ...

const app = createApp(App)

app.use(router).use(store);
app.mount('#app')

createRouter访问路由参数

<template>
  <div></div>
</template>

<script>
  import { ref } from 'vue'
  import { useRouter, useRoute, onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
  import ajax from "./ajax";

  export default {
    setup () {
      const router = useRouter()
      const route = useRoute()

      // 路由跳转 && 设置参数
      router.push({
        path: '/list',
        query: {
          id: 123,
        },
      })

      // 获取参数
      let { id } = route.query

      // 局部路由守卫
      onBeforeRouteLeave((to, from) => {
        const answer = window.confirm(
          '是否要离开本页面?'
        )
        // 取消导航并停留在同一页面上
        if (!answer) return false
      })

      const userData = ref()

      onBeforeRouteUpdate(async (to, from) => {
        //仅当 id 更改时才获取用户,例如仅 query 或 hash 值已更改
        if (to.params.id !== from.params.id) {
          userData.value = await ajax(to.params.id)
        }
      })

    },
  }
</script>

createRouter路由守卫

// 引入vue-router对象
import { createRouter, createWebHistory, ErrorHandler } from "vue-router";
/**
 * 定义路由数组
 */
const routes = [
  {// 404路由
    path: '/404',
    name: '404',
    component: ()=>import('/@/views/404.vue')
  },
];
 
/**
 * 创建路由
 */
const router = createRouter({
  history: createWebHistory("/"),
  routes,
});
 
/**
 * 路由守卫
 */
router.beforeEach((guard) => {
  beforeEach.checkAuth(guard, router);
});
 
/**
 * 路由错误回调
 */
router.onError((handler: ErrorHandler) => {
  console.log("error:", handler);
});
 
/**
 * 输出对象
 */
export default router;

createRouter动态路由

  • 新增路由
const TestRoute = () => import('@/views/vuerouter/TestRoute.vue');

  router.addRoute({
    path: '/testroute',
    component: TestRoute,
    name: 'TestRoute',
  });
  • 移除路由
// 第一种方式:通过 name 删除
router.removeRoute('TestRoute');
// 第二种方式:名字重复时自动覆盖
router.addRoute({ path: '/about', name: 'about', component: About })
// 这将会删除之前已经添加的路由,因为他们具有相同的名字且名字必须是唯一的
router.addRoute({ path: '/other', name: 'about', component: Other })
  • 添加嵌套路由,通过参数1传递⽗路由name即可
router.addRoute('parentRouteName', {...})

createRouter的基本类型

export interface _PathParserOptions {
  // 使用正则时区分大小写,默认false
  sensitive?: boolean
  // 是否禁止尾随斜杠,默认false
  strict?: boolean
  // 正则表达式前应该加^,默认true
  start?: boolean
  // 正则表达式以$结尾,默认为true
  end?: boolean
}

export type PathParserOptions = Pick<
  _PathParserOptions,
  'end' | 'sensitive' | 'strict'
>

export interface RouterOptions extends PathParserOptions {
  history: RouterHistory
  // 路由表
  routes: RouteRecordRaw[]
  // 在页面之间导航时控制滚动行为。可以返回一个 Promise 来延迟滚动。
  scrollBehavior?: RouterScrollBehavior
  // 用于自定义如何解析query
  parseQuery?: typeof originalParseQuery
  // 用于自定义查询对象如何转为字符串
  stringifyQuery?: typeof originalStringifyQuery
  // 激活RouterLink的默认类
  linkActiveClass?: string
  // 精准激活RouterLink的默认类
  linkExactActiveClass?: string
}

createRouter 相关方法

// 全局前置守卫相关方法
const beforeGuards = useCallbacks<NavigationGuardWithThis<undefined>>()
// 全局解析守卫相关方法
const beforeResolveGuards = useCallbacks<NavigationGuardWithThis<undefined>>()
// 全局后置钩子方法
const afterGuards = useCallbacks<NavigationHookAfter>()

// 当前路由,浅层响应式对象
const currentRoute = shallowRef<RouteLocationNormalizedLoaded>(
  START_LOCATION_NORMALIZED
)
let pendingLocation: RouteLocation = START_LOCATION_NORMALIZED

// 如果浏览器环境下设置了scrollBehavior,那么需要防止页面自动恢复页面位置
// https://developer.mozilla.org/zh-CN/docs/Web/API/History/scrollRestoration
if (isBrowser && options.scrollBehavior && 'scrollRestoration' in history) {
  history.scrollRestoration = 'manual'
}

// 标准化params,转字符串
const normalizeParams = applyToParams.bind(
  null,
  paramValue => '' + paramValue
)
// 编码param
const encodeParams = applyToParams.bind(null, encodeParam)
// 解码params
const decodeParams: (params: RouteParams | undefined) => RouteParams =
  applyToParams.bind(null, decode)

关于 useCallbacks

export function useCallbacks<T>() {
  let handlers: T[] = []

  function add(handler: T): () => void {
    handlers.push(handler)
    return () => {
      const i = handlers.indexOf(handler)
      if (i > -1) handlers.splice(i, 1)
    }
  }

  function reset() {
    handlers = []
  }

  return {
    add,
    list: () => handlers,
    reset,
  }
}