当前位置:   article > 正文

Vue Router框架原理及解析_vue routeconfig

vue routeconfig

 1、组件图

Matcher:组件主要是作url的匹配的。

History:是用来管理路由切换的,有三个不同的实现类,abstract, html5, hash 

2、交互

上面的图展示了从一路由切换到另一路由时,会经过NavigationGuard,以及Hooks的处理。应用层面可以在上面的处理阶段添加自定义的部分

3、路由选项

路由选项参数包含有

属性名说明
mode路由模式,支持history,hash,abstract三个值
baseurl的前缀

routes

路由数组
          pathurl路径
          component对应的组件
          name有名路由的名称
          components有名视图,类型为字符串数组或者组件
          redirect类型为字符串,Location或者函数

          props

类型为布尔,对象或者函数

         alias

类型为字符串或者字符串数组

         children

内嵌路由

         beforeEnter

进入路由前的回调,类型为函数

         meta

元数据

        caseSensitive

路由匹配是否是大小写敏感,默认是false

        pathToRegexpOptions

编译正则时路径到正则的选项

4、Matcher

路由匹配器支持路由匹配,批量添加路由,单个添加路由,获取路由记录。

4.1 路由记录

类型为RouteRecord,其类结构为

 4.1.1 路由记录的创建

createRouteMap用于创建路由记录,其在/src/create-route-map.js中定义。通过解析Router中的routes选项来创建,得到路由列表,路由的path到RouteRecord的映射关系以及有名路由的name到RouteRecord的映射关系。

  1. export function createRouteMap (
  2. routes: Array<RouteConfig>,
  3. oldPathList?: Array<string>,
  4. oldPathMap?: Dictionary<RouteRecord>,
  5. oldNameMap?: Dictionary<RouteRecord>,
  6. parentRoute?: RouteRecord
  7. ): {
  8. pathList: Array<string>,
  9. pathMap: Dictionary<RouteRecord>,
  10. nameMap: Dictionary<RouteRecord>
  11. } {
  12. // the path list is used to control path matching priority
  13. const pathList: Array<string> = oldPathList || []
  14. // $flow-disable-line
  15. const pathMap: Dictionary<RouteRecord> = oldPathMap || Object.create(null)
  16. // $flow-disable-line
  17. const nameMap: Dictionary<RouteRecord> = oldNameMap || Object.create(null)
  18. routes.forEach(route => {
  19. addRouteRecord(pathList, pathMap, nameMap, route, parentRoute)
  20. })
  21. // ensure wildcard routes are always at the end
  22. for (let i = 0, l = pathList.length; i < l; i++) {
  23. if (pathList[i] === '*') {
  24. pathList.push(pathList.splice(i, 1)[0])
  25. l--
  26. i--
  27. }
  28. }
  29. if (process.env.NODE_ENV === 'development') {
  30. // warn if routes do not include leading slashes
  31. const found = pathList
  32. // check for missing leading slash
  33. .filter(path => path && path.charAt(0) !== '*' && path.charAt(0) !== '/')
  34. if (found.length > 0) {
  35. const pathNames = found.map(path => `- ${path}`).join('\n')
  36. warn(false, `Non-nested routes must include a leading slash character. Fix the following routes: \n${pathNames}`)
  37. }
  38. }
  39. return {
  40. pathList,
  41. pathMap,
  42. nameMap
  43. }
  44. }
  45. function addRouteRecord (
  46. pathList: Array<string>,
  47. pathMap: Dictionary<RouteRecord>,
  48. nameMap: Dictionary<RouteRecord>,
  49. route: RouteConfig,
  50. parent?: RouteRecord,
  51. matchAs?: string
  52. ) {
  53. const { path, name } = route
  54. const pathToRegexpOptions: PathToRegexpOptions =
  55. route.pathToRegexpOptions || {}
  56. const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict)
  57. if (typeof route.caseSensitive === 'boolean') {
  58. pathToRegexpOptions.sensitive = route.caseSensitive
  59. }
  60. const record: RouteRecord = {
  61. path: normalizedPath,
  62. regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
  63. components: route.components || { default: route.component },
  64. alias: route.alias
  65. ? typeof route.alias === 'string'
  66. ? [route.alias]
  67. : route.alias
  68. : [],
  69. instances: {},
  70. enteredCbs: {},
  71. name,
  72. parent,
  73. matchAs,
  74. redirect: route.redirect,
  75. beforeEnter: route.beforeEnter,
  76. meta: route.meta || {},
  77. props:
  78. route.props == null
  79. ? {}
  80. : route.components
  81. ? route.props
  82. : { default: route.props }
  83. }
  84. if (route.children) {
  85. // Warn if route is named, does not redirect and has a default child route.
  86. // If users navigate to this route by name, the default child will
  87. // not be rendered (GH Issue #629)
  88. route.children.forEach(child => {
  89. const childMatchAs = matchAs
  90. ? cleanPath(`${matchAs}/${child.path}`)
  91. : undefined
  92. addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs)
  93. })
  94. }
  95. if (!pathMap[record.path]) {
  96. pathList.push(record.path)
  97. pathMap[record.path] = record
  98. }
  99. if (route.alias !== undefined) {
  100. const aliases = Array.isArray(route.alias) ? route.alias : [route.alias]
  101. for (let i = 0; i < aliases.length; ++i) {
  102. const alias = aliases[i]
  103. const aliasRoute = {
  104. path: alias,
  105. children: route.children
  106. }
  107. addRouteRecord(
  108. pathList,
  109. pathMap,
  110. nameMap,
  111. aliasRoute,
  112. parent,
  113. record.path || '/' // matchAs
  114. )
  115. }
  116. }
  117. if (name) {
  118. if (!nameMap[name]) {
  119. nameMap[name] = record
  120. }
  121. }
  122. }

RouteRecord中的regex是通过path-to-regexp库来生成的

4.2 Matcher

其在Matcher接口中定义

 4.2.1 Matcher的创建

createMatcher基于闭包创建Matcher,在文件src/create-matcher.js中定义

  1. export function createMatcher (
  2. routes: Array<RouteConfig>,
  3. router: VueRouter
  4. ): Matcher {
  5. const { pathList, pathMap, nameMap } = createRouteMap(routes)
  6. function addRoutes (routes) {
  7. createRouteMap(routes, pathList, pathMap, nameMap)
  8. }
  9. function addRoute (parentOrRoute, route) {
  10. const parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined
  11. // $flow-disable-line
  12. createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent)
  13. // add aliases of parent
  14. if (parent && parent.alias.length) {
  15. createRouteMap(
  16. // $flow-disable-line route is defined if parent is
  17. parent.alias.map(alias => ({ path: alias, children: [route] })),
  18. pathList,
  19. pathMap,
  20. nameMap,
  21. parent
  22. )
  23. }
  24. }
  25. function getRoutes () {
  26. return pathList.map(path => pathMap[path])
  27. }
  28. function match (
  29. raw: RawLocation,
  30. currentRoute?: Route,
  31. redirectedFrom?: Location
  32. ): Route {
  33. const location = normalizeLocation(raw, currentRoute, false, router)
  34. const { name } = location
  35. if (name) {
  36. const record = nameMap[name]
  37. if (!record) return _createRoute(null, location)
  38. const paramNames = record.regex.keys
  39. .filter(key => !key.optional)
  40. .map(key => key.name)
  41. if (typeof location.params !== 'object') {
  42. location.params = {}
  43. }
  44. if (currentRoute && typeof currentRoute.params === 'object') {
  45. for (const key in currentRoute.params) {
  46. if (!(key in location.params) && paramNames.indexOf(key) > -1) {
  47. location.params[key] = currentRoute.params[key]
  48. }
  49. }
  50. }
  51. location.path = fillParams(record.path, location.params, `named route "${name}"`)
  52. return _createRoute(record, location, redirectedFrom)
  53. } else if (location.path) {
  54. location.params = {}
  55. for (let i = 0; i < pathList.length; i++) {
  56. const path = pathList[i]
  57. const record = pathMap[path]
  58. if (matchRoute(record.regex, location.path, location.params)) {
  59. return _createRoute(record, location, redirectedFrom)
  60. }
  61. }
  62. }
  63. // no match
  64. return _createRoute(null, location)
  65. }
  66. function redirect (
  67. record: RouteRecord,
  68. location: Location
  69. ): Route {
  70. const originalRedirect = record.redirect
  71. let redirect = typeof originalRedirect === 'function'
  72. ? originalRedirect(createRoute(record, location, null, router))
  73. : originalRedirect
  74. if (typeof redirect === 'string') {
  75. redirect = { path: redirect }
  76. }
  77. if (!redirect || typeof redirect !== 'object') {
  78. if (process.env.NODE_ENV !== 'production') {
  79. warn(
  80. false, `invalid redirect option: ${JSON.stringify(redirect)}`
  81. )
  82. }
  83. return _createRoute(null, location)
  84. }
  85. const re: Object = redirect
  86. const { name, path } = re
  87. let { query, hash, params } = location
  88. query = re.hasOwnProperty('query') ? re.query : query
  89. hash = re.hasOwnProperty('hash') ? re.hash : hash
  90. params = re.hasOwnProperty('params') ? re.params : params
  91. if (name) {
  92. // resolved named direct
  93. const targetRecord = nameMap[name]
  94. return match({
  95. _normalized: true,
  96. name,
  97. query,
  98. hash,
  99. params
  100. }, undefined, location)
  101. } else if (path) {
  102. // 1. resolve relative redirect
  103. const rawPath = resolveRecordPath(path, record)
  104. // 2. resolve params
  105. const resolvedPath = fillParams(rawPath, params, `redirect route with path "${rawPath}"`)
  106. // 3. rematch with existing query and hash
  107. return match({
  108. _normalized: true,
  109. path: resolvedPath,
  110. query,
  111. hash
  112. }, undefined, location)
  113. } else {
  114. return _createRoute(null, location)
  115. }
  116. }
  117. function alias (
  118. record: RouteRecord,
  119. location: Location,
  120. matchAs: string
  121. ): Route {
  122. const aliasedPath = fillParams(matchAs, location.params, `aliased route with path "${matchAs}"`)
  123. const aliasedMatch = match({
  124. _normalized: true,
  125. path: aliasedPath
  126. })
  127. if (aliasedMatch) {
  128. const matched = aliasedMatch.matched
  129. const aliasedRecord = matched[matched.length - 1]
  130. location.params = aliasedMatch.params
  131. return _createRoute(aliasedRecord, location)
  132. }
  133. return _createRoute(null, location)
  134. }
  135. function _createRoute (
  136. record: ?RouteRecord,
  137. location: Location,
  138. redirectedFrom?: Location
  139. ): Route {
  140. if (record && record.redirect) {
  141. return redirect(record, redirectedFrom || location)
  142. }
  143. if (record && record.matchAs) {
  144. return alias(record, location, record.matchAs)
  145. }
  146. return createRoute(record, location, redirectedFrom, router)
  147. }
  148. return {
  149. match,
  150. addRoute,
  151. getRoutes,
  152. addRoutes
  153. }
  154. }

match时会将匹配的参数放入route的params中

  1. const route: Route = {
  2. name: location.name || (record && record.name),
  3. meta: (record && record.meta) || {},
  4. path: location.path || '/',
  5. hash: location.hash || '',
  6. query,
  7. params: location.params || {},
  8. fullPath: getFullPath(location, stringifyQuery),
  9. matched: record ? formatMatch(record) : []
  10. }

参考资料:

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

https://github.com/pillarjs/path-to-regexp

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/430373
推荐阅读
相关标签
  

闽ICP备14008679号