angular11源码探索二十一[路由Route上]

Route

定义单个路由的配置对象,一组routes 数组中,单条route 对象的配置,将给定URL与每一个路由进行匹配

interface Route {
 // 配合的路径,`**` 通配符能与任何URL匹配,`/*` 根路径,也称之为绝对路径  
  path?: string 
 // 路径匹配策略, `prefix`或者`full` 默认`prefix`(前缀), `full` 完整匹配整个URL 
  pathMatch?: string
  // 自定义URL匹配功能  
  matcher?: UrlMatcher
    // 组件
  component?: Type<any>
    // 路径匹配时重定向到的URL。如果URL以斜杠(/)开头,则为绝对值,否则相对于路径URL。如果不存在,则路由器不会重定向。
  redirectTo?: string
    // 多个出口
  outlet?: string
    //用于查找CanActivate() 处理程序的依赖项注入令牌的数组,以确定是否允许当前用户激活组件。默认情况下,任何用户都可以激活
    // 前置守卫(进入) 后置守卫(进入子组件)
  canActivate?: any[]
  canActivateChild?: any[]
  // 停止守卫(离开)  
  canDeactivate?: any[]
  // 防止异步路由  
  canLoad?: any[]
  // 直接传递数据, resolve 延迟守卫的数据也放在这里面  
  data?: Data
  //解决延迟守卫  
  resolve?: ResolveData
  children?: Routes
  // 延迟加载模块  
  loadChildren?: LoadChildren
  // 路由防护策略 
  runGuardsAndResolvers?: RunGuardsAndResolvers
}

UrlSegmentGroup

表示解析的当前URL段组。

是否有子节点
  hasChildren(): boolean {
    return this.numberOfChildren > 0;
  }
子节数
  get numberOfChildren(): number {
    return Object.keys(this.children).length;
  }
父节点
  parent: UrlSegmentGroup|null = null;
整个当前的路由节点数组
segments: UrlSegment[]
最后一个字带了s, 是整个的路由节点
  toString(): string {
    return serializePaths(this);
  }
// 这组孩子的名单
public children: {[key: string]: UrlSegmentGroup}) 

UrlMatcher

export type UrlMatcher = (segments: UrlSegment[], group: UrlSegmentGroup, route: Route) =>
    UrlMatchResult|null;
segments 当前的路段集合
group   整个的路段结合
route  当前的配置路由的对象 //{matcher: ƒ, component: ƒ}
返回值
export type UrlMatchResult = {
  consumed: UrlSegment[];
  posParams?: {[name: string]: UrlSegment};
};

consumed 是消耗的URL段的数组。
posParams 是位置参数的地图   这个还不懂

案例

export function htmlFiles(url: UrlSegment[]) {
  return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null;
}

export const routes = [{ matcher: htmlFiles, component: AnyComponent }];

url_three 源码解析

export class UrlTree {
  _queryParamMap!: ParamMap;
  constructor(
      /**总URL tree */
      public root: UrlSegmentGroup,
      /** 问好传参*/
      public queryParams: Params,
      /** #描点 */
      public fragment: string|null) {}

  get queryParamMap(): ParamMap {
    if (!this._queryParamMap) {
      this._queryParamMap = convertToParamMap(this.queryParams);
    }
    return this._queryParamMap;
  }
  toString(): string {
    return DEFAULT_SERIALIZER.serialize(this);
  }
}

路径
\angular-master\packages\router\src\url_tree.ts
我们可以通过测试文件提示里面的用法
export class DefaultUrlSerializer implements UrlSerializer {
  /** 将url解析为 `UrlTree` */
  parse(url: string): UrlTree {
    const p = new UrlParser(url);
    return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());
  }

  /** 将“UrlTree”转换为url */
  serialize(tree: UrlTree): string {
    const segment = `/${serializeSegment(tree.root, true)}`;
    const query = serializeQueryParams(tree.queryParams);
    const fragment =
        typeof tree.fragment === `string` ? `#${encodeUriFragment(tree.fragment!)}` : '';

    return `${segment}${query}${fragment}`;
  }
}

测试用法

  const url = new DefaultUrlSerializer();
  const tree = url.parse('one/two')
  url.serialize(tree)  // one/two
	
  const three=serializer.parse('/path/to?k=v&v=c')
  three.queryParams // {k: "v", v: "c"}

  const three=serializer.parse('/test?test=a&test=b&pages=5&pages=6')
    // 多个属性不会出现替换现状,而是把他变成数组
  three.queryParams // {pages: ["5", "6"],test: ["a", "b"] }

  const three = serializer.parse('/test#names')
  console.log(three.fragment);// names

  const three = serializer.parse('/test?name=xxx')
  console.log(three.queryParamMap.get('name'));// xxx

    const tree = serializer.parse('/one/two(left:three//right:four)');
    console.log(tree.root.children);
    //默认的出口 primary:segments:[UrlSegment:{parameters: {},path: "one"}, UrlSegment:{parameters: {},path: "two"}]
    //left的出口 left:segments:[UrlSegment:{parameters: {},path: "three"}]
    //right的出口 right:segments:[UrlSegment:{parameters: {},path: "four"}]

    const tree = serializer.parse('/(left:one)');
    console.log(tree.root.children['left'].segments);
    //left的出口 [UrlSegment:{parameters: {},path: "one"}]

   const tree = serializer.parse('/one/three/(two;sex=12//left:three;name=32)');
    console.log(tree.root.children['primary'].segments);
    //默认的出口 [UrlSegment:{parameters: {},path: "one"},UrlSegment:{parameters: {},path: "three"}]
    console.log(tree.root.children['primary'].children['primary']);
    //默认的出口 [UrlSegment:{parameters: {sex:12},path: "two"}]
    console.log(tree.root.children['primary'].children['left']);
    //默认的出口 [UrlSegment:{parameters: {name:32},path: "three"}]

 	  const u1 = `/one?foo=bar baz`;
      const u2 = `/one?foo=bar+baz`;
      const u3 = `/one?foo=bar%20baz`;

      const u1p = url.parse(u1);
	  u1p.queryParamMap.get('foo') // bar baz
	  后面两个结果是一样的
      const u2p = url.parse(u2);	
      const u3p = url.parse(u3);
posted @ 2021-01-14 01:10  猫神甜辣酱  阅读(183)  评论(0编辑  收藏  举报