Angular 路由学习小结

路由的概念

什么是路由

路由对于任何前端框架或库来说都是必不可少的。只加载一次应用,即可通过客户端路由向用户显示不同的内容,从而使单页应用成为可能。构建单页应用。这意味着当 URL 改变时,我们实际上并不会从服务器加载新页面。相反,路由器在浏览器中提供基于位置的导航。它允许我们在不刷新页面的情况下改变用户看到的内容以及 URL。

路由的用法

从一个简单的例子开始

  1. 当使用"ng new [app name]"命令创建一个Angular应用程序时,可以指定该程序是否是带路由的。带路由的应用会存在一个名为"app-routing.module.ts"的文件。
    在这里插入图片描述
    该文件内容如下所示:
import { NgModule} from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

// 路由配置数组
const routes: Routes = [];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
// 路由组件
export class AppRoutingModule { }

imports选项中的"RouterModule.forRoot(…)"负责注册组件和全局配置。

  1. 在路由配置数组中定义路由
    数组中的每个元素都是JavaScript对象。例如下面的定义,每个元素都包含了两个属性 path 和 component 。path 属性定义了该路由的 URL 路径,而component 属性定义了该路径应该渲染哪个组件。
const routes: Routes = [
  { path: 'first-component', component: FirstComponent },
  { path: 'second-component', component: SecondComponent },
];
  1. 在模板文件中添加路由。例如在根组件的模板中添加如下路由,并添加指令router-outlet,router-outlet是一个占位符,Angular 会根据当前的路由器状态动态填充它(准确说不是填充,而是将导航到的新组件渲染成它的兄弟节点)。
<!--省略上文-->
<ul>
  <li><a routerLink="first" routerLinkActive="active">First Component</a></li>
  <li><a routerLink="second" routerLinkActive="active">Second Component</a></li>
</ul>
<router-outlet></router-outlet>

关于路由配置数组Routes

  1. 路由顺序
    路由的顺序很重要,因为 ​Router ​在匹配路由时使用“先到先得”策略,所以应该在不那么具体的路由前面放置更具体的路由。
    通常,路由配置数组的书写顺序是:
    (1)静态路由,
    (2)与默认路由匹配的空路径路由,
    (3)通配符路由,因为它匹配每一个 URL,只有当其它路由都没有匹配时,​Router ​才会选择它。

  2. 通配符路由
    通配符路由常见的一个应用场景就是,当用户导航到一个不存在的组件时,需要向用户展示"Page Not Found"页面。此时,可以设置通配符路由,当所请求的 URL 与任何其他路由器路径都不匹配时,就会匹配到通配符路由,从而向用户展示404页面。

  3. 重定向路由
    要设置重定向,请使用重定向源的 ​path​、要重定向目标的 ​component ​和一个 ​pathMatch ​值来配置路由,以告诉路由器该如何匹配 URL。
    在Routes数组中添加一个元素如下:

{path: '', redirectTo: 'first', pathMatch: 'prefix'}

在浏览器上输入"http://localhost:4200/“,(4200是Angular服务端口号),再键Enter,会发现地址栏马上变成"http://localhost:4200/first”,即重定向到了"first"路径下。

重定向路由中,pathMatch有两个值可选,“prefix” 和 “full” :
(1)对于prefix,如果重定向源的 ​path是当前路径的前缀,则匹配成功。注意,这里的前缀不是以字符为单位进行匹配的,而是路径段。例如path = ‘a’,而当前路径是 ‘/abc’ , 则不会成功匹配。但 ‘/a/b’ 是可以成功匹配的。
(2)对于full,只有当前路径和path一样时,才能匹配成功。

  1. 子路由/嵌套路由
    随着应用变得越来越复杂,可能要创建一些相对路由。这些嵌套路由类型称为子路由。
    如果一个组件要包含子路由的话,它通常要涉及两个地方的配置。
    (1)第一个就是该组件的模板,在该组件的模板中添加<router-outlet></router-outlet>, 子组件将填充到模板中成为<router-outlet>的兄弟节点。
    (2)配置路由数组Routes,在该组件对应的元素中,添加children数组,children数组中存放子路由项。如下所示,
const routes: Routes = [
	// first-component 及其子组件的路由项
  {
    path: 'first-component',
    component: FirstComponent, // this is the component with the <router-outlet> in the template
    children: [
      {
        path: 'child-a', // child route path
        component: ChildAComponent, // child route component that the router renders
      },
      {
        path: 'child-b',
        component: ChildBComponent, // another child route component that the router renders
      },
    ],
  },
	// .....其他路由项
  ]

关于模板文件a标签上的routeLink

模板文件中的 routeLink 与 href 的之间主要的区别是:href会触发页面重载,而routeLink会告诉路由器更新 URL 并使用 <router-outlet> 指令渲染内容,而无需重载页面。

路由导航的生命周期

查看导航循环的一个好办法是订阅路由器服务的 events observable,控制台上可以看到导航生命周期。

constructor(private router: Router) {
    this.route.events.subscribe((event) => {
      console.log(event)
    });
}

在这里插入图片描述
每当路由器检测到对路由器链接指令的点击时,它就会启动导航循环。启动导航也有其他的方式,例如路由服务的 navigatenavigateByUrl 方法。路由导航会经过下图中的几个过程:
(1)应用URL重定向确定最终的URL
(2)将URL与路由树进行匹配
(3)经过路由守卫与数据解析
(4)激活组件,挂载到router-outlet挂载点
(5)导航并更新浏览器的定位
接下来将会一一详细介绍这一过程:
在这里插入图片描述

URL匹配与重定向——路由应该导航到哪个组件

首先,路由器会对路由器配置数组(我们的示例中的 ROUTES)进行深度优先搜索,并尝试将 URL 和众多路由配置项的 path 属性相匹配,同时在此过程中应用重定向。当路由器找到与URL匹配的路由项以及一个将要导航到的组件时,它发出 RoutesRecognized 事件(UsersComponent)。

路由守卫(Route Guards)——确定是否可以执行导航操作

路由守卫是布尔函数,路由器使用它来确定是否可以执行导航操作。作为开发人员,我们使用守卫(guards)来控制导航是否可以发生。例如,通过在路由配置中指定 canActivate 守卫来检查用户的登陆状态。
在路由配置数组的路由项配置canActivate属性,canActivate属性是一个any[]类型的,CanActivateGuard是守卫函数的名称。

// 路由配置数组中:
{ path: 'users', ..., canActivate: [CanActivateGuard] }

使用"ng generate guard [守卫函数的名称]" 来创建一个名为CanActivateGuard守卫函数,如下所示

import { CanActivateFn } from '@angular/router';

export const CanActivateGuard: CanActivateFn = (route, state) => {
  // .....业务操作
  return true;// 继续导航
  // return false; 取消导航
};

若守卫函数返回true,则继续导航。若守卫函数返回false,则路由器会发出NavigationCancel事件,然后中止导航。
其他的守卫(guards)包括 canLoad(模块是否被懒加载)、canActivateChildcanDeactivate(在存在表单填写的场景下,为了防止已填写的表单信息丢失,阻止用户直接从当前页面导航离开)。

路由解析器(Route Resolvers)——组件数据预取

路由解析器(Route Resolvers)可以用来提前准备组件所需要的数据,是在路由器渲染内容之前用来预取数据的函数。
路由解析器的使用:
(1)在路由配置中使用 resolve 属性指定解析器,例如下面的代码片段,名为users的数据指定给UserResolver解析。

{ path: 'users', ..., resolve: { users: UserResolver } }

(2)实现数据解析器中的resolve方法

// user.resolver.ts
export class UserResolver implements Resolve<Observable<any>> {
  constructor(private userService: MockUserDataService) {}

  resolve(): Observable<any> {
    return this.userService.getUsers();
  }
}

(3)在组件的ngOnInit函数中,通过ActivatedRoute从解析器中检索数据。

export class UsersComponent implements OnInit {
  public users = [];

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.route.data.subscribe(data => this.users = data.users);
  }
}

激活路由

激活路由就是激活路由对应的组件,并将它们渲染到<router-outlet> 指定的位置。过程大致可以分为三个步骤:
(1)从ActivatedRouteSnapshot 中提取激活的组件的信息,并创建组件实例。
(2)渲染的组件内容被放置为 <router-outlet> 的同级内容。注意,这里不是放置到 <router-outlet>内部。
(3)如果存在激活的子路由,则继续处理子路由。

更新URL

将URL更新成Final URL

// router_link.ts
private updateTargetUrlAndHref(): void {
  this.href = this.locationStrategy.prepareExternalUrl(this.router.serializeUrl(this.urlTree));
}

其他

ActivatedRouteSnapshot 和 ActivatedRoute 的区别:https://www.coder.work/article/1177189
RouterState and RouterStateSnapshot:https://blog.csdn.net/railsbug/article/details/78051152

参考
[1] https://juejin.cn/post/6844904053269331982
[2] https://www.w3cschool.cn/angular13/angular13-lg463p03.html
[3] 《Angular 权威教程》
[4] forRoot和forChild:https://www.zhihu.com/question/293728198?utm_id=0
[5] Angular 路由生命周期:https://zhuanlan.zhihu.com/p/55212010?utm_id=0
[6] https://github.com/AngularID-CN/AngularID-CN

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值