Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue-router 路由匹配机制 #24

Open
lihuakkk opened this issue Mar 18, 2020 · 0 comments
Open

vue-router 路由匹配机制 #24

lihuakkk opened this issue Mar 18, 2020 · 0 comments

Comments

@lihuakkk
Copy link
Owner

分析目标,router-view 如何正确渲染对应的组件。

路由初始化

根据我们自定义的路由规则,初始化路由项,通过遍历递归的方式建立路由索引 pathMap,nameMap,pathList 和父子路由之间的引用关系(子路由有 parent 属性,指向父路由)

// 省略一些细节,只关注核心代码逻辑
function addRouteRecord (
  pathList: Array<string>,
  pathMap: Dictionary<RouteRecord>,
  nameMap: Dictionary<RouteRecord>,
  route: RouteConfig,
  parent?: RouteRecord,
  matchAs?: string
) {
  const { path, name } = route
    // ...省略
  const record: RouteRecord = {
    // ...省略
    path: normalizedPath,
    components: route.components || { default: route.component },
    name,
    parent,
    // ...省略
  }
  ...
  if (route.children) {
    // ...省略
    route.children.forEach(child => {
      const childMatchAs = matchAs
        ? cleanPath(`${matchAs}/${child.path}`)
        : undefined
      addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs)
    })
  }
  // ...省略
}

路由匹配

路由切换的时候,都是通过 match 函数找到目标路由。

  /**
   * 可以看到这里调用_createRoute返回对应的路由项
   * 省略一些细节,只关注核心代码逻辑
   * */
  function match (
    raw: RawLocation,
    currentRoute?: Route,
    redirectedFrom?: Location
  ): Route {
    // ...省略
    const location = normalizeLocation(raw, currentRoute, false, router)
    const { name } = location
    if (name) {
      const record = nameMap[name]
      // ...省略
      return _createRoute(record, location, redirectedFrom)
    }
    // ...省略
  }

  /**
   * 调用真正的生成路由项的函数createRoute
   * */
   function _createRoute (
    record: ?RouteRecord,
    location: Location,
    redirectedFrom?: Location
  ): Route {
    // ...省略
    return createRoute(record, location, redirectedFrom, router)
  }

   /**
   * 路由项里面有一个属性matched,是由formatMatch格式化record之后返回的,后面router-view里面将用到这个* 属性来展示对应的组件
   * */
  export function createRoute (
  record: ?RouteRecord,
  location: Location,
  redirectedFrom?: ?Location,
  router?: VueRouter
): Route {
  const stringifyQuery = router && router.options.stringifyQuery
  // ...省略
  const route: Route = {
    // ...省略
    name: location.name || (record && record.name),
    params: location.params || {},
    matched: record ? formatMatch(record) : [] //
    // ...省略
  }

  return Object.freeze(route)
}

  /**
  * 根据初始化的时候建立的父子关系,返回matched的路由及其父级
  * */
function formatMatch (record: ?RouteRecord): Array<RouteRecord> {
  const res = []
  while (record) {
    res.unshift(record)
    record = record.parent
  }
  return res
}

路由展示

router-view 组件核心思想之一就是找到 router-view 之间嵌套的深度

/**
 * depth表示当前组件的层级
 * */
while (parent && parent._routerRoot !== parent) {
  const vnodeData = parent.$vnode ? parent.$vnode.data : {};
  if (vnodeData.routerView) {
    depth++;
  }
  if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {
    inactive = true;
  }
  parent = parent.$parent;
}

// ...省略
/**
 * 结合之前我们分析matched的定义和depth的概念,可以得到当前router-view需要渲染的组件
 * */
const matched = route.matched[depth];
const component = matched && matched.components[name];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant