[关闭]
@wy 2020-04-17T19:06:06.000000Z 字数 3335 阅读 514

工具函数的实现

normalizeLocation

从名字可以看出来,用来做路径规范化。需要规范化的是,path、query、hash 这些值,并把 params 值融入到路径中。

在写路由配置的 routes 时,写了路径和组件的映射关系。

看下 normalizeLocation 接收的参数和返回值:

  1. export function normalizeLocation (
  2. raw: RawLocation,
  3. current: ?Route,
  4. append: ?boolean,
  5. router: ?VueRouter
  6. ){
  7. // 其他代码暂时省略
  8. return {
  9. _normalized: true,
  10. path,
  11. query,
  12. hash
  13. }
  14. }

RawLocation 为类型

参数 raw,可以是一个字符串,也可以是对象,如果是对象,则一般是写在。

深入代码中来看:

  1. // 传入字符串,则转成对象带 path 形式,
  2. let next: Location = typeof raw === 'string' ? { path: raw } : raw
  3. // 如果已经给格式化过了,直接返回
  4. if (next._normalized) {
  5. return next
  6. } else if (next.name) { 如果有name,不需要格式化,复制后返回。
  7. next = extend({}, raw)
  8. const params = next.params
  9. if (params && typeof params === 'object') {
  10. next.params = extend({}, params)
  11. }
  12. return next
  13. }
  14. // 路径为空,并有当前路由信息对象,并且有 params,实际上就是把 params 融入到路径中。
  15. // 例如有一个配置为: {path: '/user/?id', component: User} 根据路径后面的id不同渲染出不同的人物信息,都对应同一个组件
  16. // 在组件中不跳转并改变id ,this.$roter.push({path:'',params:{id: '1'}}),这种方式的话,就符合下面的处理逻辑
  17. if (!next.path && next.params && current) {
  18. next = extend({}, next) // 复制一份,不改变原对象
  19. next._normalized = true // 添加属性,标识已格式化
  20. const params: any = extend(extend({}, current.params), next.params) // 合并改变的params到当前的params中
  21. if (current.name) { // 当前路由信息只有name,则不需要把params融入到path中
  22. next.name = current.name
  23. next.params = params
  24. } else if (current.matched.length) { // 有匹配数组
  25. const rawPath = current.matched[current.matched.length - 1].path; // 获取到最后一个匹配对象,其实就是当前访问的路径
  26. next.path = fillParams(rawPath, params, `path ${current.path}`); // 填充params到路径中
  27. } else if (process.env.NODE_ENV !== 'production') {
  28. warn(false, `relative params navigation requires a current route.`)
  29. }
  30. return next // 返回已格式化好的数据
  31. }
  32. // 如果有存在 path,说明有路径,则需要解析路径,因为路径中可能存在各种形式,例如 /path?a=1 /path?a=1#b=1&c=2
  33. // 先解析路径
  34. const parsedPath = parsePath(next.path || '')
  35. const basePath = (current && current.path) || '/'
  36. const path = parsedPath.path
  37. ? resolvePath(parsedPath.path, basePath, append || next.append)
  38. : basePath
  39. const query = resolveQuery(
  40. parsedPath.query,
  41. next.query,
  42. router && router.options.parseQuery
  43. )
  44. let hash = next.hash || parsedPath.hash
  45. if (hash && hash.charAt(0) !== '#') {
  46. hash = `#${hash}`
  47. }

fillParams

此函数的作用是,填充路径参数,得到完成的路径。

例如,需要填充的数据:

  1. let params = {
  2. id: 1,
  3. name: 'leo'
  4. }

路径:

  1. const path = '/user/:id/:name';

得到的完成路径为:

'/user/1/leo'

这里使用到了第三方模块,path-to-regexp,要自己测试的话,注意安装的版本为:1.7.0,和 vue-router 源码中安装的模块一致,否则测试时会踩坑。
地址:https://github.com/pillarjs/path-to-regexp,可查看详细用法,这里对用到的方法做简短的使用:

  1. import Regexp from 'path-to-regexp'
  2. const path = '/user/:id/:name';
  3. const filter = Regexp.compile(path);
  4. let filter = r.compile(path)
  5. const fillPath = filter({name:'leo', id: 1});
  6. console.log(fillPath)

打印的结果为:

"/user/1/leo"

作用从代码中能看出来,就是把数据填充到路径中,返回完成的路径。

明白了 path-to-regexp 的用处,再看代码变得异常简单明了

  1. /* @flow */
  2. import { warn } from './warn'
  3. import Regexp from 'path-to-regexp'
  4. // 做缓存用,对同一个路径不同求函数两次
  5. const regexpCompileCache: {
  6. [key: string]: Function
  7. } = Object.create(null)
  8. export function fillParams (
  9. path: string,
  10. params: ?Object,
  11. routeMsg: string
  12. ): string {
  13. params = params || {}
  14. try {
  15. // 得到一个填充的函数,并缓存
  16. const filler =
  17. regexpCompileCache[path] ||
  18. (regexpCompileCache[path] = Regexp.compile(path))
  19. // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
  20. // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string
  21. // 这里解决的问题,当路径为 path = '/user/*' 时,需要不断改变 * 处的值,则可以填充 pathMatch 对应的值
  22. // 例如改变路由时:{path: '/user/*', params: {pathMatch: 1}},怎会得到的完成路由时 '/user/1'
  23. if (typeof params.pathMatch === 'string') params[0] = params.pathMatch
  24. // 填充数据到路径
  25. return filler(params, { pretty: true })
  26. } catch (e) {
  27. if (process.env.NODE_ENV !== 'production') {
  28. warn(typeof params.pathMatch === 'string', `missing param for ${routeMsg}: ${e.message}`)
  29. }
  30. return ''
  31. } finally {
  32. // delete the 0 if it was added
  33. delete params[0]
  34. }
  35. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注