angular11源码探索二十六[Router整体路由配置]

Router

配置信息

class Router {
  constructor(rootComponentType: Type<any>, urlSerializer: UrlSerializer, rootContexts: ChildrenOutletContexts, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes)
    // 在此NgModule中路由事件的事件流
  events: Observable<Event>
   // 当前的路由状态
  routerState: RouterState
  errorHandler: ErrorHandler
  malformedUriErrorHandler: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
// 如果至少有一个导航事件发生,则为True。默认false
  navigated: boolean
  // 提取和合并url的策略。
  // 用于从AngularJS迁移到Angular。
  urlHandlingStrategy: UrlHandlingStrategy
  // 路由策略
  routeReuseStrategy: RouteReuseStrategy
  //forRoot 介绍过
  onSameUrlNavigation: 'reload' | 'ignore'
// 如何从父路由到子路由合并参数
// 'emptyOnly' :为无路径或无组件路由继承父参数,数据和已解析的数据。
// 'always' :继承所有子路由的父参数,数据和已解析的数据。
  paramsInheritanceStrategy: 'emptyOnly' | 'always'
  // 定义路由器何时更新浏览器URL
  // 默认 deferred  在成功导航后进行更新。如果希望在导航开始时更新URL
  // eager  尽早更新URL,可以通过显示带有失败URL的错误消息来处理导航失败
  urlUpdateStrategy: 'deferred' | 'eager'
 //空路由的相对路由报错修复机制,V11默认是corrected修复已有的 具体查看ExtraOptions
  relativeLinkResolution: 'legacy' | 'corrected'
  config: Routes
  // 当前URL
  url: string
  initialNavigation(): void
  setUpLocationChangeListener(): void
  // 检索最新的导航对象
  getCurrentNavigation(): Navigation | null
// 重置用于导航和生成链接的路线配置。
  resetConfig(config: Routes): void
  dispose(): void
  createUrlTree(commands: any[], navigationExtras: UrlCreationOptions = {}): UrlTree
  // 路由绝对导航
  navigateByUrl(url: string | UrlTree, extras: NavigationBehaviorOptions = {...}): Promise<boolean>
  //路由相对导航
  navigate(commands: any[], extras: NavigationExtras = { skipLocationChange: false }): Promise<boolean>
  //把树转成绝对路径的代码 
  serializeUrl(url: UrlTree): string
  // 输入 url字符串返回 UrlTree类型
  parseUrl(url: string): UrlTree
  // 是否激活
  isActive(url: string | UrlTree, exact: boolean): boolean
}

urlUpdateStrategy

定义路由器何时更新浏览器URL

'deferred' | 'eager'

eager 尽早更新URL,可以通过显示带有失败URL的错误消息来处理导航失败

export class TwoComponent implements OnInit {
  constructor(
    private router: Router,
    private location: Location
  ) {
    // router.urlUpdateStrategy = 'eager';
    this.router.events.subscribe(e=>{
      if (e instanceof NavigationStart) {
        console.log(location.path());
      }
        // 当路由被识别时触发的事件。
      if(e instanceof RoutesRecognized){
        console.log(location.path());
      }
    })
}  
默认情况下返回的是上一个url
例如本来的路由是`/c`=>  跳转 `/d`,  然后两个都是返回的 `/c`
// 当设置 router.urlUpdateStrategy = 'eager' 尽早更新URL
那么跳转
NavigationStart  返回的上一个 `/c`
RoutesRecognized 返回的当前的 `/d`

Router.urlHandlingStrategy

提取和合并url的策略。

urlHandlingStrategy: UrlHandlingStrategy = new DefaultUrlHandlingStrategy();
// 提供了一种将AngularJS应用迁移到Angular的方法。
export class DefaultUrlHandlingStrategy implements UrlHandlingStrategy {
    // 告诉路由器这个URL是否应该被处理。
    // 当它返回true时,路由器将执行常规导航。
    // 当返回false时,路由器将把路由器状态设置为空状态。所有的活性成分都会被销毁
  shouldProcessUrl(url: UrlTree): boolean {
    return true;
  }
  // 提取URL中应该由路由器处理的部分。URL的其余部分将保持不变。
  extract(url: UrlTree): UrlTree {
    return url;
  }
    // 将URL片段与URL的其余部分合并。
  merge(newUrlPart: UrlTree, wholeUrl: UrlTree): UrlTree {
    return newUrlPart;
  }
}

案例

// 强制不处理URL更改
 this.router.urlHandlingStrategy.shouldProcessUrl=(url:UrlTree)=> false;
// 我们发现设置之后所有的url的点击跳转都失效啦
  this.router.navigateByUrl('/home/d')

Router.getCurrentNavigation()

Router.getCurrentNavigation() 方法检索最新的导航对象 

下面是关于导航操作的信息
type Navigation = {
    // 当前导航的唯一标识符。
    id: number;
    // 导航前传递给调用的目标URL 。这是路由器解析或对其应用重定向之前的值
    initialUrl: string | UrlTree;
    // 使用解析后的初始目标
    extractedUrl: UrlTree;
    // 应用重定向后提取的URL。该网址可能不会立即可用,因此该属性可以是undefined
    finalUrl?: UrlTree;
    // 触发方式
    // 'imperative'-由router.navigateByUrl或者触发router.navigate
    // 'popstate'-由popstate事件触发。
    // 'hashchange'-由hashchange事件触发
    trigger: 'imperative' | 'popstate' | 'hashchange';
    // 用于控制用于此导航的策略。
    extras: NavigationExtras;
    // 先前成功的Navigation对象。只有一个先前的导航可用,因此该先前的Navigation对象具有null自己的值
    previousNavigation: Navigation | null;
};

//修改Router导航策略的选项
interface NavigationExtras extends UrlCreationOptions, NavigationBehaviorOptions {
  relativeTo?: ActivatedRoute | null
  queryParams?: Params | null
  fragment?: string
  queryParamsHandling?: QueryParamsHandling | null
  preserveFragment?: boolean
  skipLocationChange?: boolean
  replaceUrl?: boolean
  state?: {...}
}

使用方法

 constructor(
    private viewport: ViewportScroller,
    private router:Router
  ) {
    router.events.subscribe(e => {
      if (e instanceof NavigationEnd) {
        console.log(router.getCurrentNavigation());
      }
    });
  }

绝对路径导航

 navigateByUrl(
     url: string|UrlTree, 
     extras: NavigationBehaviorOptions = {skipLocationChange: false}
 ): Promise<boolean>
     
export interface NavigationBehaviorOptions {
  /**
   为true时,导航时不会将新状态推入历史记录。
   this.router.navigate(['/view'], { skipLocationChange: true });
   */
  skipLocationChange?: boolean;

  /**
   当为true时,在替换历史中的当前状态时进行导航
   * this.router.navigate(['/view'], { replaceUrl: true });
   */
  replaceUrl?: boolean;
  /**
  location.getState 可以查到
   */
  state?: {[k: string]: any};
}
举个小案例
         const state = {foo: 'bar'};
         router.navigateByUrl('/simple', {state});
//也可以类似多出口 router.navigateByUrl('/team/22/(user/victor//right:simple)');

路径等于当前路径时应替换状态
//  点击三次的状态
	   router.navigateByUrl('/team/33/simple');
       router.navigateByUrl('/team/22/user/victor');
       router.navigateByUrl('/team/22/user/victor');
       location.back();
	  // location.path()  '/team/33/simple'	

动态ID的技巧

    {
      path: 'd/:name', component: DComponent,
      children: [
        {path: 'a', component: AComponent},
        {path: 'c/:age', component: CComponent, outlet: 'left'},
      ]
    },
        
DComponent
     
<p>d works!</p>
<router-outlet></router-outlet>
<router-outlet name="left"></router-outlet>

    this.router.navigateByUrl('/d/123/(a//left:c/123)')
只用left出口
    this.router.navigateByUrl('/home/d/123/(left:c/123)')
// 这种情况
    this.router.navigateByUrl('/home/d/123/a(left:F)')
					// ()是这种在根路由添加一个left的新路由出口, 实际开发中用到的概率不高

父空路由多出口出现报错的问题

  path: '', component: TwoComponent, children: [
        {path: 'a', component: AComponent},
        {path: 'c', component: CComponent},
        {
          path: 'd', component: DComponent,
          outlet: 'right'
        },
   ] 
TwoComponent的html记得导入出口
 <router-outlet name="right"></router-outlet>
我们发现当使用 navigateByUrl会报错
this.router.navigateByUrl('/(c//right:d)')
但是当我们父路由不是空路由就可以正常使用
   {
      path: 'd', component: DComponent,
      children:[
        {path: 'c', component: CComponent},
        {path: 'a', component: AComponent,outlet:'right'},

      ]
    },
    this.router.navigateByUrl('/home/d/(c//right:a)')

这个时候如何解决这种问题呢?

其实我们可以尝试使用navigate, 然后我试过了,发现还是报错,那么暂时我思考的点

如果多出口的情况下,父路由不应该为空

功能丰富的导航

navigate(
    commands: any[], 
    extras: NavigationExtras = { skipLocationChange: false }
): Promise<boolean>
    
导航策略   
interface NavigationExtras extends UrlCreationOptions, NavigationBehaviorOptions {

  // inherited from router/UrlCreationOptions
  relativeTo?: ActivatedRoute | null
  queryParams?: Params | null
  fragment?: string
  queryParamsHandling?: QueryParamsHandling | null
  preserveFragment?: boolean

  // inherited from router/NavigationBehaviorOptions
  skipLocationChange?: boolean
  replaceUrl?: boolean
  state?: {...}
}

案例
router.navigate(
             ['/a'],
    {queryParams: {a: true}, queryParamsHandling: 'merge', replaceUrl: true});
相对的
router.navigate(['team', 33, 'user', 11], {relativeTo: route});

多入口
  {path: 'c', component: CComponent,children:[
        {path: 'd', component: DComponent,outlet:'left'},
        {path: 'e', component: EComponent},
   ]},
router.navigate([{outlets: {left: 'd',primary:'e'}}], {relativeTo: this.route});
我们发现把值设置为null,我们的left出口没了
this.router.navigate([{outlets: {left: null,primary:'e'}}], {relativeTo: this.route});
// 当问号传参设置的undefined/null
    this.router.navigate(['/home/d'],{queryParams:{name:1,age:null,page:undefined}})
	//结果 /home/d?name=1

动态id跳转

	   [
           {path: 'old/team/:id', redirectTo: 'team/:id'},
           {path: 'team/:id', component: TeamCmp}
         ]

         location.go('old/team/22');
		//  	/team/22

resetConfig

重置用于导航和生成链接的路线配置。

记住重点**重置**和**生成**

export class OneComponent implements OnInit {
  constructor(
        private router:Router
  ) {
    router.resetConfig([{path: 'show', component: DComponent}]);
  }
  clickDown() {
    this.router.navigate(['/show']);
  }
} 
<a [routerLink]="['./c']">ccc</a> <br>
<a [routerLink]="['./d']">ddd</a> <br>
<button (click)="clickDown()">Click</button>
<p>

我们发现/show 可以跳转,也就是新的导航, 之前的导航重置啦

posted @ 2021-01-21 09:46  猫神甜辣酱  阅读(448)  评论(0编辑  收藏  举报