Angular路由模块config配置

1,244 阅读4分钟

在配置根路由时,可以对路由进行一系列的配置,具体的配置项写在RouterModule.forRoot(routes: Route[], config?: ExtraOptions)的 config

首先我们看看ExtraOptions接口是什么

interface ExtraOptions {
  enableTracing?: boolean
  useHash?: boolean
  initialNavigation?: InitialNavigation
  errorHandler?: ErrorHandler
  preloadingStrategy?: any
  onSameUrlNavigation?: 'reload' | 'ignore'
  scrollPositionRestoration?: 'disabled' | 'enabled' | 'top'
  anchorScrolling?: 'disabled' | 'enabled'
  scrollOffset?: [number, number] | (() => [number, number])
  paramsInheritanceStrategy?: 'emptyOnly' | 'always'
  malformedUriErrorHandler?: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree
  urlUpdateStrategy?: 'deferred' | 'eager'
  relativeLinkResolution?: 'legacy' | 'corrected'
}
  1. enableTracing是一个boolean,将其配置为ture时可以将内部导航事件记录到控制台,下面是配置后打印的结果

    const routes: Routes = [
      { path: 'first-component', component: FirstComponent },
      { path: 'second-component', component: SecondComponent },
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes,{
        enableTracing: true
      })],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
    
    <!--  组件省略  -->
    <div>
        <a nz-button routerLink="/first-component" routerLinkActive="active">组件一</a> &nbsp;
        <a nz-button routerLink="/second-component" routerLinkActive="active">组件二</a>
    </div>
    

    image-20210726201510558.png

    上面的图可以清晰的看到整个导航过程中,事件触发的先后顺序

  2. useHash:boolean 修改位置策略,用 URL 片段(#)代替 history API, 设定使用哈希模式还是使用history模式,默认为false,使用history

  3. initialNavigation 设置导航在AppComponent创建前开始还是创建后开始, 默认是enabledNonBlocking:在创建根组件之后开始初始导航,引导程序不会被阻止。 enabledBlocking:初始导航在创建根组件之前开始,引导程序将被阻止,该值是让服务器渲染正常工作所必需的。

    image-20210726204300360.png

  4. errorHandler 导航失败的自定义错误处理器。当路由发生错误时,可以捕获错误

    1. 当不捕获错误时,如果匹配路由失败时会如以下报错

    image-20210726205135478.png 2. 自定义错误处理函数

    // 自定义ErrorHandle
    class MyErrorHandler implements ErrorHandler {
      handleError(error: any) {
        console.warn('当路由发生错误时,可以自定义错误处理函数')
      }
    }
    
    // App.module.ts
    @NgModule({
      ...
      providers: [
        { provide: ErrorHandler, useClass: MyErrorHandler } // 声明token,这样就可以自己实现路由错误处理函数了
      ],
      ...
    })
    
  5. preloadingStrategy 配置预加载策略,在程序空闲时尽快预加载所有模块。

    1. 当你需要采用这种预加载策略时,你只需要在RouterModule.forRoot中配置preloadingStrategy

      @NgModule({
        imports: [RouterModule.forRoot(routes, {
          preloadingStrategy: PreloadAllModules
        })]
      })
      

      image-20210727140736911.png

    2. 你也可以自定义预加载模式,比如程序加载完毕3秒后加载预加载模块

      // app-routing.module.ts
      const routes: Routes = [
        { path: 'first-component', component: FirstComponent },
        { path: 'second-component', component: SecondComponent },
        { 
          path: 'load', 
          loadChildren: () => import('./load/load.module').then(m => m.LoadModule),
          data: {
            preload: true // 用data中的preload作为标示判断是否采用PreloadAllModules模式
          },
        },
        { 
          path: 'home', 
          loadChildren: () => import('./home/home.module').then(m => m.HomeModule),
          data: {
            preload: true, // 用data中的preload作为标示判断是否采用PreloadAllModules模式
            delay: 3000 // 3000毫秒后加载,如果当前访问的路由是home模块下的page则立即加载
          },
        },
      ];
      
      // app.module.ts 
      class ServicePreloadingStrategy implements PreloadingStrategy {
        preload(route: Route, load: () => import("rxjs").Observable<any>): Observable<any> {
          return route.data && route.data.preload ? timer(route.data.delay || 0).pipe(
            mergeMap(() => load())
          )
          : of(null);
        }
      }
      // 这样home模块就会在程序运行完毕后3秒再加载对应模块
      @NgModule({
        ...
        providers: [
          { provide: PreloadingStrategy, useClass: ServicePreloadingStrategy },
        ],
        ...
      })
          
      
  6. onSameUrlNavigation 导航到当前 URL 的请求时该如何处理,默认的情况会忽略本次导航,但是如果你是进行刷新操作,则不会忽略

    1. 两种模式,默认是ignore 当你配置为reload 时导航将不会忽略

      @NgModule({
        ...
        imports: [RouterModule.forRoot(routes, {
          onSameUrlNavigation: 'reload' // 采用reload模式,默认是ignore模式
        })],
        ...
      })
      
      export class HomePageComponent implements OnInit {
        constructor(
          private router: Router,
          private route: ActivatedRoute
        ) {
          this.route.url.subscribe(console.log) // 采用reload模式后,调用goSelf方法,url会再次被订阅到值
          // 如果你设置了enableTracing: true,则可以再次看到URL跳转时触发函数的整个周期。
         }
        goSelf(){
          this.router.navigateByUrl('/home/home-page')
        }
      }
      
  7. scrollPositionRestoration 配置是否需要在导航回来的时候恢复滚动位置

    1. 默认是disabled什么也不做,top 每次导航回来都把滚动位置设置为 x=0, y=0。enabled 当向后导航时,滚动到以前的滚动位置

    2. 如果你想导航回来时,滚动到上次的位置

      @NgModule({
        ...
        imports: [RouterModule.forRoot(routes, {
          scrollPositionRestoration: 'enabled' // 恢复上次滚动的位置
        })],
        ...
      })
      
    3. 你可以自定义恢复滚动策略

      export class AppComponent {
        constructor(
          private router: Router,
          viewportScroller: ViewportScroller
        ){
          this.router.events.pipe(
            filter(e=> e instanceof Scroll)
          ).subscribe(route=>{
            route = route as Scroll;
            if (route.position){
              viewportScroller.scrollToPosition(route.position) // route会记住上次导航离开的position,当再次导航回来时,可以将滚动条设置到记忆的位置
            }else if(route.anchor){
              viewportScroller.scrollToAnchor(route.anchor)
            }else{
              viewportScroller.scrollToPosition([0,0])
            }
          })
        }
      }
      
  8. anchorScrolling 如果 URL 有一个片段,就滚动到锚点元素

    1. 导航回来,滚动到指定的元素

    2. 默认为disabled 禁止滚动到锚点,如果你设置了enabled 则可以滚动到指定元素

      @NgModule({
        imports: [RouterModule.forRoot(routes, {
          anchorScrolling: 'enabled',
        })],
        ...
      })
      
      // home-page.component.ts
      export class HomePageComponent implements OnInit {
        constructor(
          private router: Router
        ) {
        }
        goSelf(){
          this.router.navigate(['home','home-page'],{
            fragment: 'top'
          })
        }
      }
      
      
      <!-- home-page.component.html ->
      <div class="home-page">
          <button nz-button (click)="goSelf()">跳转到自己</button><br/>
          <a [routerLink]="['/home/home-page']" fragment="top">跳转到自己</a>
          <h1 id="top">目标元素</h1>
      </div>
      
  9. scrollOffset 配置当滚动到一个元素时,路由器使用的滚动偏移

    1. 一般会搭配上面的 anchorScrolling 使用,在滚动到指定元素的基础上再进行偏移

        imports: [RouterModule.forRoot(routes, {
          anchorScrolling: 'enabled',
          scrollOffset: [0,100] // 向下偏移100px
        })],
      
  10. paramsInheritanceStrategy 定义路由器如何将参数、数据和已解析的数据从父路由合并到子路由

    1. 默认情况下 emptyOnly 继承无路径或无组件路由的父参数,例如

      const routes: Routes = [
        {
          path: 'second-component/:pid',
          component: SecondComponent,
          children: [
            { path: '', component: SecondIndexComponent}, // 这种无路径的路由会合并到子路由
            { path: 'child', component: SecondChildComponent}, // 有路径的就无法合并子路由
          ]
        },
      ];
      
    2. 使用 always 选项后会始终启用父参数的无条件继承

      // 当我们在SecondChildComponent中想获取pid的参数是就需要配置always
      @NgModule({
        imports: [RouterModule.forRoot(routes, {
          paramsInheritanceStrategy: 'always',
        })],
        exports: [RouterModule]
      })
      
      // second-child.component.ts
      export class SecondChildComponent implements OnInit {
        constructor(
          private route: ActivatedRoute
        ) { }
      
        ngOnInit(): void {
          console.log('params', this.route.snapshot.params); // 配置了'always'才能拿到pid
        }
      }