[Angular] Day21. Common Routing Tasks (一)

上一张介绍完什麽是 router 与他的基本用法之後,接着要来继续介绍 Angular router 的其他一些比较详细的细节与用法,那就接着看下去吧!

https://ithelp.ithome.com.tw/upload/images/20210819/20124767pIY0V2tSzX.png


What is URL?

URL 是浏览器用来检索网路上任何已发布资源的机制,他的全名叫做 Uniform Resource Locator,理论每个有效的 URL 都会指向一个唯一的资源,URL 是由不同部分所组成的,一部分是一定要有而另一部分则是可选的,他的组成为下图

https://ithelp.ithome.com.tw/upload/images/20210819/20124767g2R4tJ6Uli.png

Scheme

https://ithelp.ithome.com.tw/upload/images/20210819/20124767bxYRnYkWD2.png

URL 的第一部分是 scheme 他表示浏览器请求资源时所使用的通讯协议,对於网站而言通常是使用 httphttps,除了网站常用的这两个之外他也知道该如何处理其他方案,比如说填入 mailto 就打开邮件功能等等。

Authority

https://ithelp.ithome.com.tw/upload/images/20210819/20124767a13Y5g4IxU.png

接下来是 Authority 他通过字串 :// 与 Scheme 分开,Authority 部份包括 Domain NamePort 两个部分组成,两者由冒号(:)分隔

  • domain 表示正在请求的 web 服务器,通常会是一个 domain name 也可以使用 IP Adress
  • Port 代表访问 Web 服务器上资源的 gate,使用 HTTP 为 80 而 HTTPS 为 443,不过如果是使用 HTTP 协议的标准来授与对其资源的访问权限时通常会省略他

Path to resource

https://ithelp.ithome.com.tw/upload/images/20210819/20124767rr4ZuNbS50.png

上面例子中的 path to resource 是 Web 服务器上资源的路径,在早期这样的路径代表 Web 服务器上的物理文件路径。

Parameters

https://ithelp.ithome.com.tw/upload/images/20210819/20124767c0mygWppvq.png

parameters 是用来提供 Web 服务器的额外参数,这些参数是由 & 与 / 分隔,Web 服务器可以透过这些参数再回传资源前做额外的处理。

Anchor

https://ithelp.ithome.com.tw/upload/images/20210819/20124767YuHmZFJj9n.png

Anchor 代表资源内的一种书签,为浏览器提供显示位置於该书签的位置,例如在 HTML 中新增带有 id 的标题,当点击某个标题时可以将浏览器瞬间移动到那个标签那边,要注意的是 # 後面的部分永远不会随 request 一起发送到服务器中。


Getting route information

虽然了解了如何使用基本的 router 但似乎对於开发专案来说还是不太够,可能会遇到再开发专案时需要将信息从一个 component 传递到另一个 component ( 这边不是向父子层传递参数,是 component 的平行传递 ),比如说一个显示购物清单的应用程序,每个商品项目都有一个唯一的 id,要编辑某个商品的内容时使用者要点及编辑按钮,打开 EditGroceryItem component,希望将 component 的商品 id 传入以便向使用者显示整却的信息。

遇到这个情况就可以使用 router 将信息传递给你需要的 component,为此可以使用 ActivatedRoute interface 该怎麽使用就来举个例子吧,一样拿上一篇的 router 例子来改写就好

  1. 首先先更改 app-routing.module.ts 中的设定

    import { NgModule } from '@angular/core';
    import { RouterModule, Routes, ActivatedRoute, ParamMap } from '@angular/router';
    import { FirstComponent } from './first/first.component';
    import { SecondComponent } from './second/second.component';
    
    const routes: Routes = [
      { path: 'first-component/:name', component: FirstComponent },
      { path: 'second-component/:name', component: SecondComponent }
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
    

    在 routes 的阵列中设定每个 component 对应到的路径,这边将路经更改为 componentName/:name ,经过上面对 URL 的介绍就会知道我们希望在 path 中添加 parameters。

  2. 在 app.component.html 中调整点击按钮後送出的 url path

    <!-- app.component.html -->
    
    <h1>Angular Router App</h1>
    <nav>
      <ul>
        <li><a routerLink="/first-component/first-one-component" routerLinkActive="active">First Component</a></li>
        <li><a routerLink="/second-component/second-one-component" routerLinkActive="active">Second Component</a></li>
      </ul>
    </nav>
    <router-outlet></router-outlet>
    
  3. 接着在这两个 component 中新增方法来获得 url 传递的参数

    import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';                 // (1)
    
    @Component({
      selector: 'app-first',
      templateUrl: './first.component.html',
    })
    export class FirstComponent implements OnInit {
      name!: string | null;                                           // (2)
      constructor( private route: ActivatedRoute,) { }                // (3)
    
      ngOnInit(): void {
        this.name = this.route.snapshot.paramMap.get('name')          // (4)
      }
    }
    
    import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';
    
    @Component({
      selector: 'app-second',
      templateUrl: './second.component.html',
    })
    export class SecondComponent implements OnInit {
      name!: string | null;
      constructor( private route: ActivatedRoute,) { }
    
      ngOnInit(): void {
        this.name = this.route.snapshot.paramMap.get('name')
      }
    }
    
    • (1): 从 @angular/router 中引入 ActivatedRoute
    • (2): 建立一个 property 用於接收 url 的参数并显示在画面中
    • (3): 将 ActivatedRoute 注入到 component 中
    • (4): 获得 url 的参数
  4. 接着在两个 component 的 template 中显示获得的 name

    <h1>Component Name is: {{name}}</h1>
    

img

在画面中可以看到随着我们点击不同的超连结会进到不同的 component 中,而画面中的内容会随着 url 的参数改变,就代表 component 确实有获得 url 的参数并将它显示在各自的 view 中。


Setting up wildcard routes

再开发这种有使用 router 的专案时,需要注意要能够正常的处理当使用者输入了专案中不存在路径时会发生什麽事,要处理这种情况需要将 wildcard route 添加到你的设定中,每当请求的 url 与任何一个路径不匹配时 Angular 就会选择这个路径

{ path: '**', component:  }

两个星号(**) 向 Angular 表明这个 route 是 wildcard route,对於 component property 则可以使用任一 component 不过通常会多做一个 component 用来处理这种状况,比较常见的是建立一个 PageNotFoundComponent 来向使用者显示 404 或重新导向首页之类的,记得要将 wildcard route 放在最後一条,因为他会匹配任何一个 url。

来用上面的例子新增一个 PageNotFoundComponent 吧

const routes: Routes = [
  { path: 'first-component/:name', component: FirstComponent },
  { path: 'second-component/:name', component: SecondComponent },
  { path: '**', component: PageNotFoundComponent  }
];

接着在 pageNotFound.component.html 中新增显示没有此页面

<h1>Page Not Found</h1>

img
可以看到当输入了一个不符合任何 route 的路径时会导向 pageNotFoundComponent。


Nesting routes

随着专案变大单纯的一层 route 已经不够应付复杂的专案架构,这时就需要 nesting routes 的出现,他可以让你 <router-outlet> 中显示的 component 中也有自己的 <router-outlet>,因为他是对 AppComponent 中的 <router-outlet> 的补充,以上面的例子来说除了 app.component 中有 <router-outlet> 用来显示 firstComponent 或 secondComponent 之外,还可以在 firstComponent 在添加自己的 <router-outlet>

  1. 先在 firstComponent 中添加自己的 <router-outlet>

    <!-- first.component.html -->
    
    <h1>Component Name is: {{name}}</h1>
    <nav>
      <ul>
        <li><a routerLink="child-a">Child A</a></li>
        <li><a routerLink="child-b">Child B</a></li>
      </ul>
    </nav>
    
    <router-outlet></router-outlet>
    
  2. 接着在 app-routing.module.ts 中添加 nesting routes

    const routes: Routes = [
      {
        path: 'first-component/:name',
        component: FirstComponent,
        children: [
          { path: 'child-a', component: ChildAComponent },
          { path: 'child-b', component: ChildBComponent },
        ],
      },
      { path: 'second-component/:name', component: SecondComponent },
      { path: '**', component: PageNotFoundComponent },
    ];
    

img

画面中可以看到只有选择 First Component 後才会出现 Child-a 与 Child-b 两个导览列,各自点选 Child-a 或 Child-b 後就会显示对应的 component view。


结论

本章中介绍了什麽是 url 以及他的结构,对於现代网页而言 url 是非常重要的观念,需要充分的了解他的结构与该怎麽使用它。

介绍了如何透过 url 传递参数让符合路径的 component 可以获得参数,介绍了如何利用 wildcard route 建立 pageNotFoundComponent,用於处理当使用者输入了不属於本专案的 route 路径时该怎麽处理,记得要将它放在所有 route 的最後面,因为他会匹配所有的路径,至於路径匹配的优先权会在明天讲解,最後介绍了如何做嵌套 route,在符合 route 路径的 component 中也能有属於他自己的 <router-outlet>

由於 route 的章节比较多,所以无法一次在本篇中全部介绍所以将它分为两篇,这样会对每个例子或用法可以比较深入了介绍他的用法与功能,明天也会是介绍 Angular route 的下半部,会介绍如何使用相对路径、Lazy loading 和其他好用的功能,那就明天见吧


Reference


<<:  【Day 12】使用 Systems Manager 的 Parameter Store 保存变数

>>:  Day08:部门与工程团队间协作的技巧(下)

连续 30 天 玩玩看 ProtoPie - Day 26

https://www.protopie.io/blog/keyboard-shortcut-tip...

[Day27] React - 建立子元素

建立子元素 React.createElement("标签名称",{属性obje...

Day 2.来交朋友吧!-Vue.js是谁?

Vue 由前 Google 工程师尤雨溪在 2014 年 2 月所建立的一套开放源码(Open So...

Day29 资料流重新导向II

昨天我们聊到可以将指令执行的结果导向到档案里面,那我们其实就可以利用这个特性,制作一个垃圾桶黑洞装置...

10 | WordPress 图片区块 Image Block | 双色调滤镜 (Duotone Filter)

使用双色调并不是十麽新鲜的事情,最早可以追溯到 60 年代,传统的单色印刷或之後随着数码技术日渐流...