电商商城定制开发【vue-router源码】四、createRouter源码解析

【vue-rouer源码】系列文章

  1. 【vue-router源码】四、createRouter源码解析

目录


前言

【vue-router源码】电商商城定制开发系列文章将带你从0开始了解vue-router电商商城定制开发的具体实现。电商商城定制开发该系列文章源码参考vue-router v4.0.15
源码地址:
电商商城定制开发阅读该文章的前提是你最好了解vue-router电商商城定制开发的基本使用,如果你没有使用过的话,可通过学习下。

该篇文章将带你分析createRouter的实现。

使用

const routerHistory = createWebHistory()export const router = createRouter({  history: routerHistory,  strict: true,  routes: [    { path: '/home', redirect: '/' },    {      path: '/',      components: { default: Home, other: component },      props: { default: to => ({ waited: to.meta.waitedFor }) },    },    {      path: '/nested',      alias: '/anidado',      component: Nested,      name: 'Nested',      children: [        {          path: 'nested',          alias: 'a',          name: 'NestedNested',          component: Nested,          children: [            {              name: 'NestedNestedNested',              path: 'nested',              component: Nested,            },          ],        },        {          path: 'other',          alias: 'otherAlias',          component: Nested,          name: 'NestedOther',        },        {          path: 'also-as-absolute',          alias: '/absolute',          name: 'absolute-child',          component: Nested,        },      ],    },  ],  async scrollBehavior(to, from, savedPosition) {    await scrollWaiter.wait()    if (savedPosition) {      return savedPosition    } else {      if (to.matched.every((record, i) => from.matched[i] !== record))        return { left: 0, top: 0 }    }    return false  },})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

createRouter

在分析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}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

我们来看下createRouter具体做了什么。createRouter方法共885(包含空行)行,乍一看可能会觉得方法很复杂,仔细观察,其实很大一部分代码都是声明一些函数。我们可以先暂时抛开这些函数声明看其余部分。

首先会使用createRouterMatcher方法创建了一个路由匹配器matcher,从options中提取parseQuerystringifyQueryhistory属性,如果options中没有history,抛出错误。

const matcher = createRouterMatcher(options.routes, options)const parseQuery = options.parseQuery || originalParseQueryconst stringifyQuery = options.stringifyQuery || originalStringifyQueryconst routerHistory = options.historyif (__DEV__ && !routerHistory)    throw new Error(      'Provide the "history" option when calling "createRouter()":' +        ' https://next.router.vuejs.org/api/#history.'    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

紧接着声明了一些全局守卫相关的变量,和一些关于params的处理方法,其中有关全局守卫的变量都是通过useCallbacks创建的,params相关方法通过applyToParams创建。

// 全局前置守卫相关方法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/scrollRestorationif (isBrowser && options.scrollBehavior && 'scrollRestoration' in history) {  history.scrollRestoration = 'manual'}// 标准化params,转字符串const normalizeParams = applyToParams.bind(  null,  paramValue => '' + paramValue)// 编码paramconst encodeParams = applyToParams.bind(null, encodeParam)// 解码paramsconst decodeParams: (params: RouteParams | undefined) => RouteParams =  applyToParams.bind(null, decode)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

关于useCallbacks的实现:在useCallbacks中声明一个handlers数组用来保存所有添加的方法,useCallbacks的返回值中包括三个方法:add(添加一个handler,并返回一个删除handler的函数)、list(返回所有handler)、reset(清空所有handler

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,  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

applyToParams的实现:接收一个处理函数和params对象,遍历params对象,并对每一个属性值执行fn并将结果赋给一个新的对象。

export function applyToParams(  fn: (v: string | number | null | undefined) => string,  params: RouteParamsRaw | undefined): RouteParams {  const newParams: RouteParams = {}  for (const key in params) {    const value = params[key]    newParams[key] = Array.isArray(value) ? value.map(fn) : fn(value)  }  return newParams}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

然后声明了大量的函数,包括addRouteremoveRoutegetRoutes等,这些函数也就是我们日常使用的addRouteremoveRoute等。

createRouter的最后创建了一个router对象,并将其返回,该对象几乎包含了声明的所有函数。

总结

createRouter函数中声明了一些全局钩子所需的变量和很多函数,这些函数就是我们日常使用的一些方法,如addRouteremoveRoute等,在函数的最后,声明了一个router对象,前面所声明的函数多数都会被包含在这个对象里,最终会将router返回。在router中有个重要的install方法,关于install的过程可以看之前的文章,这里就不再次介绍了。
对于router中的各个函数,会在后续文章中继续介绍。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发