Angular路由的一些思考与验证

Angular路由的一些思考与验证,第1张

文章目录 1. 路由的组成2. 如何指定相对路由?在 html 中在 ts 中 3. RouterLink路由参数链接参数数组几种写法的示例 4. Router什么时候用 navigateByUrl?什么时候用 navigate? 5. ActivatedRoute 查询路由数据什么时候用 params ?什么时候用 queryParams ?什么时候用 snapshot 快照? 6. replaceUrl:true的用法7.LocationStrategy 路由策略

1. 路由的组成

2. 如何指定相对路由? 在 html 中

在html中使用相对路径来指定相对路由。
/ 开头的形式,路由器会从应用的 根路由 开始查找。
./无前导斜线 形式是相对于 当前级别 的。
../ 会回到当前路由路径的 上一级 。(比如:可以使用…/回到上一级,然后再进入兄弟路由路径中。)

<a routerLink="../second-component">Relative Route to second componenta>
在 ts 中

在ts中用 Router.navigate 方法配合 NavigationExtras 中的 relativeTo 属性来指定相对路由。我们必须提供当前的 ActivatedRoute ,来让路由器知道我们现在位于路由树中的什么位置。

constructor(
  private router: Router,
  private route: ActivatedRoute
) {}

goToItems() {
  // navigate方法的参数2是NavigationExtras对象。把该对象的relativeTo属性设置为当前的ActivatedRoute,也就是this.route 。
  this.router.navigate(['items'], { relativeTo: this.route });
}
3. RouterLink 路由参数

RouterModule中带参数的路由定义:

{ path: 'hero/:id', component: HeroDetailComponent }

在视图中设置路由参数:

<a [routerLink]="['/hero', hero.id]">


<router-outlet>router-outlet>
链接参数数组

3种形式:


<a [routerLink]="['/heroes']">Heroesa>



<a [routerLink]="['/hero', hero.id]">a>



<a [routerLink]="['/crisis-center', { foo: 'foo' }]">Crisis Centera>

几种写法的示例

示例A:相对于当前路径级别进行导航。


<a [routerLink]="['overview']">概览a>
<a [routerLink]="['logs']">日志a>



<a [routerLink]="['./overview']">概览a>
<a [routerLink]="['./logs']">日志a>

以上不等同于以下:



<a [routerLink]="['/overview']">概览a>
<a [routerLink]="['/logs']">日志a>

示例B:相对于上一级路径进行导航,使用 ../





<a [routerLink]="['../settings/basic']">基本设置a>


<a [routerLink]="['../settings/', 'basic']">基本设置a>


<a [routerLink]="['../settings', 'basic']">基本设置a>


const viewId = 'basic'
<a [routerLink]="['../settings', basic]">基本设置a>

示例C:设置路由参数。




<ng-container *ngFor="let view of views">
	<a href="javascript:;" [routerLink]="['../', view._id]">{{ view.name }}a>
ng-container>

// ts
views = [
    { _id: 'all', name: '全部视图' },
    { _id: 'viewA', name: '视图A' },
    { _id: 'viewB', name: '视图B' },
    { _id: 'viewC', name: '视图C' }
];

示例D:使用矩阵URL标记法,在对象中传可选参数。




<a [routerLink]="['../settings/basic', { user: 'wumeimin', age: 18 }]">基本设置a>

示例E:指定路由的查询参数。




<a [routerLink]="['../settings/basic']" [queryParams]="{ user: 'wumeimin', age: 18 }">基本设置a>
4. Router 什么时候用 navigateByUrl?

当调用路由器的 Router.navigateByUrl() 时,url必须要指定完整的绝对路径。

navigateByUrl(url: string | UrlTree, extras: NavigationBehaviorOptions = {...})

什么时候使用?在不想基于当前路由树位置进行导航时使用。比如:

// 当前正处于页面 /xxx/xxxx/insights/default
// 要点击按钮跳转到绝对路径 /xxx/xxxx/itemDetail
this.router.navigateByUrl('/xxx/xxxx/itemDetail');
什么时候用 navigate?

基于所提供的 命令数组(参数1)起点路由(在参数2的relativeTo指定) 进行 相对或绝对 导航。

navigate(commands: any[], extras: NavigationExtras = { skipLocationChange: false })

第二个参数NavigationExtras支持我们设置:

interface NavigationExtras extends UrlCreationOptions, NavigationBehaviorOptions {

  // 允许从当前激活的路由进行相对导航。
  // 如果传ActivatedRoute,则从当前激活路由进行相对导航。
  // 如果没指定值,则从根路由进行绝对导航。
  relativeTo?: ActivatedRoute | null  ⭐️⭐️⭐️
  
  // 设置URL的查询参数
  queryParams?: Params | null   ⭐️⭐️
  
  // 设置url的哈希片段(#)
  fragment?: string   ⭐️⭐️          
  
  // 设置如何在路由器链接中处理查询参数以进行下一个导航。 
  // preserve:保留当前参数,将放弃所有新的查询参数。 比如:从 /view1?page=1 到 /view2?page=1
  // merge:合并新的当前参数,将新的查询参数附加到当前URL的参数中。比如:从 /view1?page=1 到 /view2?page=1&otherKey=2
  queryParamsHandling?: QueryParamsHandling | null  ⭐️⭐️⭐️
  
  // 在后续导航时保留 # 片段。 比如:从 /results#top 到 /view#top
  preserveFragment?: boolean

  // 值为true则导航时不把新状态记入历史
  skipLocationChange?: boolean
  
  // 值为true则导航时不把”当前状态“记入历史
  replaceUrl?: boolean   ⭐️⭐️⭐️
  state?: {...}
}

示例A:使用navigate进行相对或绝对导航。

<!-- 场景:当前页面处于/xxx/xxxx/overview,当点击”日志“时,会导航到/xxx/xxxx/logs -->
<a [routerLink]="['overview']">概览</a>
<a [routerLink]="['logs']" (click)="toLogs()">日志</a>

// ts中以下几种写法均可达到目的

// 方式一:navigate相对导航 (relativeTo值为true时相对于当前激活路由进行导航)
this.router.navigate(['logs'], { relativeTo: this.route });
// 同:
this.router.navigate(['.', 'logs'], { relativeTo: this.route });
// 同:
this.router.navigate(['./', 'logs'], { relativeTo: this.route });
// 同:
this.router.navigate(['./logs'], { relativeTo: this.route });

// 方式二:navigate绝对导航 (relativeTo值为null时。命令数组需要能拼成一个完整的绝对路径)
this.router.navigate(['/xxx/xxxx/logs']);

// 方式三:navigateUrl绝对导航(需要提供绝对路径)
this.router.navigateByUrl('/xxx/xxxx/logs');

// 错误写法(该写法会从根路由/开始匹配,路由会瞬间跳到'/logs',由于没有匹配的,然后会被一路重定向到别的页面)
this.router.navigate(['logs']);
5. ActivatedRoute 查询路由数据

ActivatedRoute用于跟踪路由数据。

params 和 queryParams 的区别?
(1)params :表示当前路由范围内的矩阵参数 ; ,对应的映射是paramMap。
(2)queryParams :表示所有路由共享的查询参数 ? ,对应的映射是queryParamMap。

相同点:ActivatedRoute.params,ActivatedRoute.paramMap,ActivatedRoute.queryParams,ActivatedRoute.queryParamMap 都返回Observable。

什么时候用 params ?

场景一:获取矩阵URL中的可选参数。
矩阵 URL标记法:在链接参数数组中,可以在对象中提供可选的路由参数。参数在URL中将以 ; 的形式出现。在导航到的组件中通过 paramsparamMap 获取 可选参数 的数据。

<!-- 当前页面处于/xxx/xxxx/xxxxx/hahaha/viewId -->
<!-- 点击”基本设置“跳转到 /xxx/xxxx/xxxxx/hahaha/settings/basic;user=wumeimin;age=18 -->

<a [routerLink]="['../settings/basic', { user: 'wumeimin', age: 18 }]">基本设置</a>
// 也可以使用navigate
this.router.navigate(['../settings/basic', { user: 'wumeimin', age: 18 }], { relativeTo: this.route });



// 在导航到的组件中获取参数
import { ActivatedRoute, ParamMap } from '@angular/router';

// 方式一:使用paramMap获取(在参数发生变化时触发发射新值)
this.route.paramMap.subscribe((param: ParamMap) => {
    console.log(param);  // 返回的是一个ParamMap对象{params: {user: 'wumeimin', age: '18'}},它提供了get、getAll、has、keys等方法
    param.get('user')    // wumeimin
    param.get('age')     // 18
    param.getAll('user') // ['wumeimin']
    param.has('user')    // true
    param.keys           // ['user', 'age']
});


// 方式二:使用params获取
this.route.params.subscribe((param: { user: string; age: number }) => {
    console.log(param); // 返回的是 { user: 'wumeimin', age: 18 }
    param.user          // wumeimin
    param.age           //  18
});  

// 注意:使用queryParams或queryParamMap获取不到上述数据。


场景二:跟踪一般场景下的路由参数变化。
RouterMoulde中的路由定义:

{
    path: 'insight',
    children: [
        {
            path: '',
            pathMatch: 'full',
            redirectTo: 'all'
        },
        {
            path: ':viewId',
            component: MyViewContainerComponent
        }
    ]
}

视图中路由参数的设置:

// 场景:当前页面在 /xxx/xxxx/xxxxx/insight/all
// 点击”视图A“,会跳转到 /xxx/xxxx/xxxxx/insight/viewA

views = [
    { _id: 'all', name: '全部视图' },
    { _id: 'viewA', name: '视图A' },
    { _id: 'viewB', name: '视图B' },
    { _id: 'viewC', name: '视图C' }
];

<ng-container *ngFor="let view of views">
	<a href="javascript:;" [routerLink]="['../', view._id]">{{ view.name }}</a>
</ng-container>


// 也可以使用 navigate
<ng-container *ngFor="let view of views">
	<a href="javascript:;" (click)="toView(view._id)">{{ view.name }}</a>
</ng-container>

toView(viewId) {
    this.router.navigate(['../', viewId], { relativeTo: this.route });
}

在导航到的组件中使用ActivatedRoute的params或paramMap获取路由参数viewId:

// 方式一:使用paramMap获取
this.route.paramMap.subscribe((param: ParamMap) => {
    const viewId = param.get('viewId');
});

// 方式二:使用params获取
this.route.params.subscribe((param: { viewId: string }) => {
	const viewId = param.viewId;
});


// 注意:使用queryParams或queryParamMap获取不到上述数据,因为这俩是用来订阅“查询参数”的。

什么时候用 queryParams ?

场景一: 用于获取查询参数。
在RouterLink中可以使用 queryParams 将查询参数添加到生成的URL。参数在URL中将以 ? 的形式出现,在导航到的组件中通过 queryParams 或 queryParamMap 获取 查询参数 的数据。

<!-- 场景:当前页面处于/xxx/xxxx/xxxxx/backlog/viewId -->
<!-- 点击”基本设置“跳转到 /xxx/xxxx/xxxxx/settings/basic?user=wumeimin&age=18 -->

<a [routerLink]="['../settings/basic']" [queryParams]="{ user: 'wumeimin', age: 18 }">基本设置</a>
// 也可以使用 navigate
this.router.navigate(['../settings/basic'], { relativeTo: this.route, queryParams: { user: 'wumeimin', age: 18 } });



// 在导航到的组件中获取参数
import { ActivatedRoute, ParamMap} from '@angular/router';

// 方式一:使用queryParamMap获取(在查询参数发生变化时才会触发发射新值)
this.route.queryParamMap.subscribe((queryParam: ParamMap) => {
    console.log(queryParam);   // 返回的是一个ParamMap对象,{params: {user: 'wumeimin', age: '18'}},它提供了get、getAll、has、keys等方法
    queryParam.get('user')     // wumeimin
    queryParam.get('age')      // 18
    queryParam.getAll('user')  // ['wumeimin']
    queryParam.has('user')     // true
    queryParam.keys            // ['user', 'age']
});

// 方式二:使用queryParams获取
this.route.queryParams.subscribe((queryParam: { user: string; age: number }) => {
    console.log(queryParam);      // 返回的是 { user: 'wumeimin', age: 18 }
    console.log(queryParam.user); // wumeimin
    console.log(queryParam.age);  //  18
});

// 注意:使用params或paramMap获取不到上述数据,因为这俩是用来订阅“路由参数”的。

什么时候用 snapshot 快照?

当要导航到的组件不会被复用时,即当不需要检测路由变化时我们可以直接使用 snapshot 快照来访问路由数据, snapshot 快照只能访问到初始值

const id = this.route.snapshot.paramMap.get('user');

const id = this.route.snapshot.param.user;

const id = this.route.snapshot.param['user'];

当要导航到的组件会随着路由参数的变化被复用时,我们不用 snapshot 快照,而是需要使用订阅者。由于 ngOnInit() 在每个组件实例化时只会被调用一次,所以需要使用 paramMap可观察对象 来检测路由参数在同一个实例中何时发生了变化。

import { ActivatedRoute, ParamMap } from '@angular/router';
import { switchMap } from 'rxjs/operators';

constructor(
  private route: ActivatedRoute,
  private service: HeroService
) {}

ngOnInit() {
   this.hero$ = this.route.paramMap.pipe(
    switchMap((params: ParamMap) =>
      // 检测到路由参数变化,拿取最新参数来进行下一步的数据更新 *** 作
      this.service.getHero(params.get('id')!))
  );
}

// 此示例中 switchMap  *** 作符做了两件事。它把 HeroService 返回的 Observable 拍平,并取消以前的未完成请求。
// 当 HeroService 仍在检索旧的 id 时,如果用户使用新的 id 重新导航到这个路由,switchMap 会放弃那个旧请求,并返回新 id 的英雄。

一般在组件订阅可观察对象,通常需要在组件销毁时取消这个订阅。 但ActivatedRoute 中的可观察对象是一个例外,因为 ActivatedRoute 及其可观察对象与 Router 本身是隔离的。 Router 会在不再需要时销毁这个路由组件,这意味着此组件的所有成员也都会销毁,包括注入进来的 ActivatedRoute 以及那些对它的所有 Observable 属性的订阅。

6. replaceUrl:true的用法

导航时使用 replaceUrl: true ,不把”当前状态“记入历史。当浏览器回退时,会跳过这个没被记录进历史的状态。示例验证:

<ng-container *ngFor="let view of views">
	<a href="javascript:;" (click)="toView(view._id)">{{ view.name }}</a>
</ng-container>

views = [
    { _id: 'all', name: '全部视图' },
    { _id: 'viewA', name: '视图A' },
    { _id: 'viewB', name: '视图B' },
    { _id: 'viewC', name: '视图C' }
];

toView(viewId) {
    if (viewId === 'viewA') {
        // 在导航到viewA之前,不把“当前状态”记录进历史。(这里,从哪进入的viewA,哪就是当前状态)
        this.router.navigate(['../', viewId], { relativeTo: this.route, replaceUrl: true });
    } else {
        this.router.navigate(['../', viewId], { relativeTo: this.route });
    }
}

7.LocationStrategy 路由策略

两种路由策略:

// PathLocationStrategy策略:HTML 5 pushState 风格
localhost:3002/crisis-center/

// HashLocationStrategy策略:hash URL 风格
localhost:3002/src/#/crisis-center/

RouterModule.forRoot() 使用的是默认策略PathLocationStrategy。
几乎所有的 Angular 项目都会使用默认的 HTML 5 风格。它生成的 URL 更易于被用户理解,它也为将来做服务端渲染预留了空间。

现代 HTML 5 浏览器支持 history.pushState API, 这是一项可以改变浏览器的当前地址和历史,却又不会触发服务端页面请求的技术。

必须在应用的 index.html 中添加一个 元素才能让 pushState 路由正常工作。 浏览器要用 的值来为引用 CSS、脚本和图片文件时使用的相对 URL 添加前缀。

<base href="/">

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/925109.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存