5

路由过程的7个步骤

每次点击链接或浏览器URL改变时,Angular路由器都会确保应用程序做出相应的反应。

为了做到这一点,Angular路由器执行以下7个步骤的顺序:

  1. 解析(Parse):它解析用户要导航到的浏览器URL。

  2. 重定向(Redirect):它应用URL重定向(如果定义了一个)

  3. 标识(Identify):它标识哪个路由器状态对应于URL。

  4. 警卫(Guard):它运行在路由器状态中定义的守卫。

  5. 解析(Resolve):它解决路由器状态所需的数据。

  6. 激活(Activate):它激活Angular组件来显示页面。

  7. 管理(Manage):它管理导航,并在请求新URL时重复该过程。

记住这7个步骤,您可以使用助记PRIGRAM,其中每个字母代表路由过程中的一步:

  • Parse

  • Redirect

  • Identify

  • Guard

  • Resolve

  • Activate

  • Manage

在我们深度了解每一步之前,让我们回顾一下,Angular路由器的使用术语。

术语

路由服务(router service): 我们应用程序中的Angular全局路由服务

路由器配置(router configuration):我们应用程序中的所有可能的路由器状态的定义

路由器状态(router state):路由器在某个时间点的状态,表示为激活的路由快照树。

激活的路由快照(activated route snapshot):提供对路由器状态节点的URL、参数和数据的访问

守护(guard):在加载、激活或停用路由时运行的脚本(script)。

解析器(resolver):在请求页面被激活之前获取数据的脚本

路由器插座(router outlet):在DOM中,Angular路由器可以放置激活组件的位置

URL片段(URL segments):URL斜杠部分

如果你不熟悉Angular路由器或任何这些术语听起来陌生,我强烈建议你先阅读Use Angular router to resolve data官方路由指导或Angular主力作者Victor Savkin的书Angular Router

步骤1 解析浏览器URL

就Angular路由器而言,浏览器URL是表示路由器状态的字符串。由于路由器状态是一棵树,Angular路由器本质上考虑了浏览器URL的序列化树。

在路由过程的第1步中,Angular路由器将浏览器URL解析为URL树。

URL树是一种数据结构,稍后将帮助Angular路由器识别步骤3中的路由器状态树。

为了解析URL,Angular使用以下约定:(注:冒号前面是路由器出口,后面是URL片段)

  • / => 斜线划分URL片段

  • () => 括号指定次要路径。

  • : => 冒号指定一个指定的路由器出口。

  • ; => 一个分号指定一个矩阵参数。

  • ? => 一个问号分隔查询字符串参数。

  • '#'=> 一个#号标签列举片段。

  • '//'=> 双斜线分割多个次要路径。

例如,在解析下面的URL时:

/section-one;test=one/(nav:navigation;test=two//main:about;test=three)?query=four#frag

angular识别出以下部分(点击这里获取更大的版本):

anatomy-of-angular-router-url

  • 'section-one', 'navigation' 和 'about' 是URL片段

  • ';test=one', ';test=two' 和 ';test=three' 是矩阵参数

  • '(nav:navigation;test=two)' 是次要路由,列出了出口路由'nav'的 URL片段'navigation',以及分配了自己的矩阵参数test,值为字符串类型的'two'

  • (main:about;test=three) 是次要路由,列出了出口路由'main'的 URL片段'about',以及分配了自己的矩阵参数test,值为字符串类型的'three'

  • '//' 用于分隔二级路由。

  • '?query=four' 分配查询字符串变量'query',字符串值为'four'

  • '#frag' 分配了片段'frag'

矩阵参数的范围是在路由同级(Matrix parameters are scoped on a route level. )。不同的路由可以具有相同名称和不同值的矩阵参数。

相反,查询字符串参数和URL片段的范围不在路由同级(query string parameters and the fragment are not scoped on a route level)。它们通过路由共享,因此它们的名称应该是唯一的。

一旦Angular路由器组装了URL树,它将继续到步骤2。

步骤2 重定向

在Angular路由器使用URL树创建路由器的状态之前,它会检查对应的重定向规则。

有两种不同的重定向类型:

  • local redirect:

    • 当 'redirectTo' 不是以 '/' 开始

    • 替换成单个URL片段

    • 例如: { path: 'one', redirectTo: 'two' }

  • absolute redirect:

    • 当 'redirectTo' 是以 '/' 开始

    • 替换整个URL

    • 例如: { path: 'one', redirectTo: '/two' }

Angular路由器遍历路由器配置。一旦找到匹配的重定向,重定向就被应用,路由器继续到步骤3。

只有一种重定向规则被应用!

如果路由1重定向到路由2,路由2重定向到路由3,然后路由2重定向路由3不执行,路由2被激活。(If route 1 redirects to route 2, which in turn redirects to route 3, then the second redirect to route 3 is not performed and route 2 is activated.)

步骤3 识别路由器状态

此时,Angular路由器拥有一个潜在重定向应用程序的URL树。

Angular路由器遍历URL树,并与路由器配置中配置的路径匹配URL片段。

如果URL片段与路由的路径匹配,则路由的子路由与剩余的URL片段匹配,直到所有URL片段匹配为止。

如果没有找到完全匹配的路由器,回溯到在下一个兄弟的路由找到匹配。

思考下面的路由器配置:

[
  {
    path: 'one',
    component: OneComponent,
    children: [
      {
        path: 'two/three',
        component: OtherComponent
    ]
  }
]

和下面的URL:

/one/two/three

然后Angular路由器会找到一个由两条路由组成的匹配:

  • 路径为'one' 的路由与一个URL片段匹配

  • 路径为'two/three' 的子路由与两个URL片段匹配

一旦Angular路由器找到一个完整的匹配,消耗所有的URL段,路由器状态被构造,路由器继续到步骤4。

请注意,Angular路由器没有路由精度的概念。一旦找到完整的匹配,Angular路由器停止处理配置。因此,确保您的路由按正确的顺序配置是很重要的。如果您将通配符路由作为第一个路由添加,则不会到达其他路由,通配符路由将始终匹配。因此,您应该始终将通配符路由添加为路由器配置中的最后一条路由。

如果整个路由器配置被处理且没有匹配,则路由器导航失败并记录错误。

步骤4 路由守卫 - 运行路由守卫

现在Angular路由器知道要路由哪个路由器状态,它就运行相关的守护程序来检查是否允许导航到新的路由器状态。

首先,它从'最深的子路由'到'顶级'的顺序运行下面的守卫进程:

  • CanDeactivate

  • CanActivateChild

然后, 它从'顶级'到'最深的子路由'的顺序运行下面的守卫进程:

  • CanActivate

如果新的路由器状态需要一个模块被延迟加载,那么下面的守护进程也是运行的:

  • CanLoad

一个守护者必须返回一个布尔值或一个承诺/可观察到的值,该值解析为布尔值。

当守护进程返回false值,导航就会被取消。

如果没有一个守卫返回一个false值,Angular路由器继续到步骤5。

步骤5 Resolve - 运行resolvers

因为Angular路由器知道新的路由器的状态可以被激活,它运行相关的resolvers。

在配置过程中,可以使用路由的数据属性将静态数据附加到路由:

{
  path: 'one',
  component: OneComponent,
  data: {
    name: 'Jazz'
  }
}

它允许你在运行时动态地解析数据。然后将新解析的数据合并到数据属性中的现有静态数据中:

path: 'one',  
component: OneComponent,  
data: {  
  name: 'Jazz'
},
resolve: {

  // Return value of AddressResolver will be merged in data
  // and will be available as data.address
  address: AddressResolver
}

resolver 是一个函数或类,具有一个返回值、一个承诺或一个可观察对象。如果解析器返回一个承诺或一个可观察对象,Angular路由器在它继续到步骤6之前等待它完成。

一旦所有的resolve都已完成,其返回值是合并的路径的data property, 然后Angular路由器继续步骤6。

步骤6 激活组件

在这步里,Angular路由器实例化所需组件并将它们放在DOM中<router-outlet>元素正确的相应路由器出口 。

如果一个组件已经在以前的路由器状态实例化过或者仅仅路由参数发生改变,那么组件就不会重新实例化。但是组件同样被重新激活( reactivated ), 而且新的参数可以通过可观察对象activatedroute进行使用。

当所有组件被实例化或重新激活时,Angular路由器会更新浏览器URL中的URL。

步骤7 管理导航

最后,当新的路由器状态被显示到屏幕上时,Angular路由器侦听URL更改和状态更改。

一旦发生下列情况之一:

  • 用户更改浏览器URL

  • 用户点击一个链接(使用 routerlink

  • 执行导航命令(使用 router.navigate

Angular路由器重复整个过程。

总结

在这篇文章中我们学到了当用户导航从一个页面到另一个的时候,Angular路由器都做了哪些过程。

你可以使用助记 PRIGRAM

  • Parse

  • Redirect

  • Identify

  • Guard

  • Resolve

  • Activate

  • Manage

记住Angular路由器经过的步骤的顺序。

了解这个过程将有助于您更好地了解幕后发生的事情,并帮助您调试潜在的路由问题。

下次有人问你,Guard之前或Resolve之后发生了什么,你会知道该说什么。

希望有读者喜欢!

参考资源



HanSummer
74 声望7 粉丝

人生如风,戏如JS --重新开始