美文网首页
(译)angular路由完全指南

(译)angular路由完全指南

作者: 哈维尔23456 | 来源:发表于2018-12-20 14:13 被阅读0次

    摘要:在本教程中,Ahmed Bouchefra 介绍了angular路由器(router),以及如何使用它创建客户端应用和带路由导航的单页面应用。


    如果你对angular7还不熟悉的话,我将带你近距离了解这个令人印象深刻的前端框架所提供的一切。我会向你演示一个angular demo,通过这个demo你将了解与路由相关的一些概念,比如:

    • 路由出口(The router outlet)
    • 路由(Routes )和 路径(paths)
    • 导航(Navigation)

    我也将向你演示如何使用Angular CLI v7生成一个demo应用,在这个应用中,我们将使用angular路由器实现路由和导航。但在介绍angluar路由之前,让我们一起重温一下angular以及它在最新版本中增加的一些新特性。


    Anguar7 的介绍

    angular是最受欢迎的构建移动端和pc端应用的前端框架之一,它遵循基于组件的体系结构,其中每个组件都是一段独立的、可重用的代码,控制着应用程序UI的一部分。

    angular中的每一个组件都是一个用@Component装饰器装饰的TypeScritp类。它有一个附加模板和用于形成组件视图的css样式表。

    angular7是angular最近刚发布的最新版本,它给angular带来了很多新特性,尤其是在CLI和性能表现方面有了很大的提升,比如:
    ·CLI提示: 像 ng add 和ng new 这样的普通命令现在可以提示用户选择要向项目中添加的命令,比如路由和样式格式

    • Angular Material CDK添加虚拟滚动功能
    • Angular Material CDK添加对拖放功能的支持
    • 新项目会默认使用CLI中的Budgets Bundle ,这将在app大小超过限定尺寸时向开发者发出警告。默认情况下,当初始 bundle 超过2MB,新应用程序将发出警告,超过5MB时将会报错。你也可以在angular.json文件中修改这些限制值。

    Angular Router 介绍

    Angular Router是由angular 核心团队构建和维护的一款强大的JavaScript路由器,可以从@angular/router包中安装使用。它给开发者提供了一个拥有众功能的完整的路由库,这些功能包括 多路由出口,不同的路由匹配策略,易获取的路由参数,保护组件免受未授权访问的路由守卫。

    Angular Router是angular平台的核心部分,它使得开发者能够使用多个视图构建单页面应用,并允许在这些视图之间导航。

    现在,让我们来更详细的了解路由器的基本概念。


    路由出口(the router-outlet)

    router-outlet 是路由库中提供的一个指令,路由器根据当前浏览器的URL插入相匹配的组件。你可以在你的应用中加入多个outlet来实现高级的路由场景

    <router-outlet></router-outlet>
    

    路由器将把它匹配的任何组件呈现为路由出口的同级组件


    路由和路径(routes and paths)

    Routes 是一系列定义(对象集)(译者注:也就是路由配置对象的集合),每个对象包含至少一个path属性和一个component属性(或者一个redirectTo属性)。path指URL中确定应该显示的唯一视图的部分,component指需要与path相关联的angular组件。根据我们提供的一个路由定义(通过静态方法RouterModule.forRoot(routes)),路由器能够将用户导航到特定的视图

    每个路由将一个URL路径映射到唯一对应的组件

    path的值可以为空(''),这表示应用的一个默认路径,空路径通常是应用的开始。

    path的值可以使用通配符字符串(**)。如果请求的URL无法匹配路由数组中任何定义的路由,路由器将会选择通配符路由。通配符路由可以用来展示"Not Found"视图,或者在没有路由匹配的情况下重定向到特定的视图

    下面是一个路由的例子:

    { path:  'contacts', component:  ContactListComponent}
    

    如果将这个路由添加到路由器配置中,当web应用程序的浏览器URL变为 /contacts时,路由器将呈现ContactListComponent组件。


    路由匹配策略

    angular路由器提供了多种不同的路由匹配策略。默认的策略是检查当前浏览器URL是否以定义的path值为前缀。
    例如我们的上一个路由:

    { path:  'contacts', component:  ContactListComponent}
    

    也可以写成下面的形式:

    { path:  'contacts',pathMatch: 'prefix', component:  ContactListComponent}
    

    pathMatch属性指定了路由匹配策略,默认值是例子中的prefix.
    pathMatch的另一个值是full,当指定一个路由的匹配策略为full时,路由器将检查path的值是否与当前浏览器URL完全匹配:

    { path:  'contacts',pathMatch: 'full', component:  ContactListComponent}
    

    路由参数

    创建带参数的路由是webapp的一个常见特性,Angular路由器允许你使用一下两种不同的方式访问路由参数:

    你可以使用冒号语法创建一个路由参数,下面是一个带有id参数的路由例子:

    { path:  'contacts/:id', component:  ContactDetailComponent}
    

    路由守卫

    路由守卫是angular的路由器的一个特性,它允许开发者在一个路由被请求时运行一些处理逻辑,并根据运行结果决定允许或者拒绝用户访问此路由。路由守卫普遍被用在用户访问一个页面时,检查用户是否已登录并被授权。

    你可以通过实现@angular/router模块中的CanActive接口,重写canActivate()方法来添加路由守卫。canActivate()方法用于存放是否允许访问路由的处理逻辑的。下面的守卫将始终允许用户访问一个路由:

    class MyGuard implements CanActivate {
      canActivate() {
        return true;
      }
    }
    

    然后,你可以使用canActive属性将路由守卫添加到路由上,达到保护路由的目的:

    { path:  'contacts/:id', canActivate: [MyGuard], component:  ContactDetailComponent}
    

    导航指令

    angular路由器提供了routerLink指令来创建导航链接。这个指令采用路由中与组件相关联的路径进行导航,形式如下:

    <a [routerLink]="'/contacts'">Contacts</a>
    

    多路由出口和辅助路由

    angular路由器支持在同一应用中使用多个路由出口(outlet)。

    每个组件都有一个相关联的主路由,也可以有多个辅助路由。辅助路由是开发者能够同时导航多个路由。

    要创建辅助路由,你需要一个被命名的路由出口,与辅助路由相关联的组件将会在这个命名的路由出口渲染。

    <router-outlet></router-outlet>
    <router-outlet name="outlet1"></router-outlet>
    
    • 没有name属性的路由出口为主路由出口
    • 除了主路由出口外,所有的路由出口都应该有一个name

    然后,你可以使用outlet属性指定你想渲染你的组件的那个路由出口:

    { path: "contacts", component: ContactListComponent, outlet: "outlet1" }
    

    创建一个 angular7 Demo

    在这一部分,我们将看到一个如何安装和使用angular路由器的实际例子。这里是我们将创建的demo演示以及github项目地址

    安装angular7

    使用Angular CLI需要Nodejs 8.9+版本,npm 5.5.1+版本,开发前确保你的系统中安装了它们。然后运行下面的命令行安装最新版的Angular CLI

    $ npm install -g @angular/cli
    

    这条命令将会全局安装Angular CLI

    Note: 你或许想使用sudo命令全装安装angluar-cli,这取决于你的npm配置


    创建一个angular7 项目

    简单的运行下面这条命令,就可以创建一个新的项目:

    $ ng new angular7-router-demo
    

    CLI会询问你是否想添加路由(输入N拒绝,因为我们将会在demo看到如何手动添加路由),想使用哪种样式表,选择css ,然后按下Enter。CLI将会创建包含项目必需文件的文件夹目录,安装项目所需的依赖。


    创建虚拟后台(fake back-end)服务

    因为我们没有真实的后台可以交互,所以我们使用angular-in-memeory-web-api库来创建一个虚拟后台。这个库是angluar用来演示和测试的内存中的web api,它模拟了REST API的CRUD操作.

    这个库的工作方式是拦截HttpClient向远程服务器发送的请求,并将请求重定向到我们创建的本地内存数据存储区。

    为了创建一个虚拟后台,我们需要遵循以下步骤:

    01 安装 angular-in-memeory-web-api模块
    02 创建一个返回假数据的服务
    03 配置应用程序使用虚拟后台

    在终端输入下面的命令安装angular-in-memory-web-api模块:

    $ npm install --save angular-in-memory-web-api
    

    然后,生成一个将要使用的后台服务:

    ng g s backend
    

    打开 src/app/backend.service.ts文件,从angular-in-memory-web-api模块中引入 InMemoryDbService:

    import {InMemoryDbService} from 'angular-in-memory-web-api'
    

    前面生成的BackendService服务需要实现InMemoryDbService接口并重写里面的createDb()方法:

    @Injectable({
      providedIn: 'root'
    })
    export class BackendService implements InMemoryDbService{
    
      constructor() { }
      createDb(){
        
       let  contacts =  [
         {  id:  1,  name:  'Contact 1', email: 'contact1@email.com' },
         {  id:  2,  name:  'Contact 2', email: 'contact2@email.com' },
         {  id:  3,  name:  'Contact 3', email: 'contact3@email.com' },
         {  id:  4,  name:  'Contact 4', email: 'contact4@email.com' }
       ];
    
       return {contacts};
        
      }
    }
    

    我们在BackendService中简单的创建了一个联系人数组并返回了他们,每一个联系人都有一个id属性。

    最后,我们将InMemoryWebApiModule模块引入到app.module.ts中,并提供我们创建的BackendService:

    import { InMemoryWebApiModule } from “angular-in-memory-web-api”;  
    import { BackendService } from “./backend.service”;
    /* ... */
    
    @NgModule({
      declarations: [
        /*...*/
      ],
      imports: [
        /*...*/
        InMemoryWebApiModule.forRoot(BackendService)
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
    

    接下来创建一个ContactService服务,它封装了处理联系人的代码:

    $ ng g s contact
    

    打开src/app/contact.service.ts文件,将它修改为下面的内容:

    import { HttpClient } from “@angular/common/http”;
    
    @Injectable({
      providedIn: 'root'
    })
    export class ContactService {
    
      API_URL: string = "/api/";
      constructor(private http: HttpClient) { }
      getContacts(){    
       return this.http.get(this.API_URL + 'contacts')
      }
      getContact(contactId){
       return this.http.get(`${this.API_URL + 'contacts'}/${contactId}`) 
      }
    }
    

    ContactService中,我们添加了两个方法:

    • getContacts() - 获取全部联系人
    • getContact() - 通过id获取某一联系人

    你可以将 API_URL设置成任何URL值,因为我们不会使用一个真实后台。所有的请求都将被拦截并发送到我们所创建的虚拟后台中。


    创建我们的 Angular组件

    在我们学习如何使用不同的路由特性之前,让我们先为我们的项目创建一些组件。

    打开终端运行下面的这些命令:

    $ ng g c contact-list
    $ ng g c contact-detail
    

    这两条命令将会生成一个ContactListComponent组件和一个ContactListComponent组将。将它们添加到根模块中(译者注:此模块位于 app.module.ts文件中)

    配置路由模块

    在大多数情况下,你会使用Angular CLI创建带路由配置的项目,但在这里,我们将手动添加路由,如此一来我们能够更好的理解angular中的路由是如何工作的。

    添加路由模块

    我们需要添加AppRoutingModule,它包含我们的应用程序路由和一个路由器出口,Angular将根据浏览器的当前URL插入当前匹配的组件。

    我们将会看到:

    • 如何为路由创建一个angular模块并引入它
    • 如何为不同的组件配置路由
    • 如何配置路由出口

    首先,让我们在一个 app-routing.module.ts中创建路由模块,在src/app路径下使用如下命令创建app-routing.module.ts文件:

    $ cd angular7-router-demo/src/app
    $ touch app-routing.module.ts
    

    译者注:
    touch可能是作者使用的linux创建文件的命令,读者可以直接在src/app目录下使用angular中自带的ng g m app-routing命令创建此路由模块文件,然后根据作者下面的步骤修改此文件即可

    打开app-routing.module.ts文件,将它修改为如下内容:

    import { NgModule } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    
    const routes: Routes = [];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
    
    

    上述代码中,我们首先从@angular/core包中引入了NgModule,这是一个用来创建Angular模块的TypesScript装饰器。

    我们还从@angular/core包引入了RouterModule类和Routes类。
    RouterModule提供了像RouterModule.forRoot()这样的静态方法,用于将配置对象传递个路由器。

    接下来,我们定义了一个类型为Routes的常量数组routes用来存放每一个路由的信息。

    最后,我们创建并导出了一个名为AppRoutingModule的模块(你可以起任何你喜欢的名字),这个模块是一个由@NgModule装饰器装饰的简单的TypeScript类,@NgModule 装饰器接受一个元数据对象,该对象的属性用来描述这个模块。在这个对象的 imports属性中,我们调用了RouterModule.forRoot(routes)方法,并将路由数组作为参数传了进去。在exports数组中,我们添加了RouterModule.


    引入路由模块

    接下来,我们将刚才创建的路由模块引入位于src/app/app.module.ts文件的根模块中:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        AppRoutingModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    

    我们从./app-routing.module中引入了AppRoutingModule,并将它添加到了根模块的imports数组中。


    添加路由出口

    最后,我们需要添加路由出口(router outlet)。打开包含了主应用模板的src/app/app.component.html文件,添加<router-outlet>

    <router-outlet></router-outlet>
    

    Angular路由器将在这里渲染与当前浏览器路径相对应的组件。

    以上是在angular项目中手动配置路由所需要遵循的所有步骤。

    创建路由

    现在,让我们给我们的两个组件添加路由。打开src/app/app-routing.module.ts,将下面的路由添加到routes数组中:

    const routes: Routes = [
       {path: 'contacts' , component: ContactListComponent},
       {path: 'contact/:id' , component: ContactDetailComponent}
    ];
    

    要确保在路由模块中引入了这两个组件:

    import { ContactListComponent } from './contact-list/contact-list.component';
    import { ContactDetailComponent } from './contact-detail/contact-detail.component';
    

    现在,我们就可以通过/contactscontact:id访问这两个组件了。

    添加导航链接

    接下来,让我们使用routerLink指令将导航链接添加到我们的app模板上。打开src/app/app.component.html,在<router-outlet></router-outlet>上面添加如下代码:

    <h2><a [routerLink] = "'/contacts'">Contacts</a></h2>
    

    接下来,我们需要在ContactListComponent组件中展示联系人列表。打开 src/app/contact-list.component.ts,然后添加如下代码:

    import { Component, OnInit } from '@angular/core';
    import { ContactService } from '../contact.service';
    
    @Component({
      selector: 'app-contact-list',
      templateUrl: './contact-list.component.html',
      styleUrls: ['./contact-list.component.css']
    })
    export class ContactListComponent implements OnInit {
    
      contacts: any[] = [];
      
    
      constructor(private contactService: ContactService) { }
    
      ngOnInit() {
        this.contactService.getContacts().subscribe((data : any[])=>{
            console.log(data);
            this.contacts = data;
        })
      }
    }
    

    我们创建了一个contacts数组来存放联系人数据,接下来,我们在该组件中注入ContactService服务,在ngOnInit钩子函数中调用服务实例的getContacts()方法来获取联系人数据(前文BackendService中创建的fake data)并将它赋值给contacts数组。
    下一步,打开src/app/contact-list/contact-list.component.html文件,添加如下代码:

    <table style="width:100%">
      <tr>
        <th>Name</th>
        <th>Email</th>
        <th>Actions</th>
      </tr>
      <tr *ngFor="let contact of contacts" >
        <td>{{ contact.name }}</td>
        <td>{{ contact.email }}</td> 
        <td>
        <a [routerLink]="['/contact', contact.id]">Go to details</a>
        </td>
      </tr>
    </table>
    

    我们遍历contacts数组并展示每一个联系人的姓名和email.同时,我们也使用routerLink指令创建了一个指向每一个联系人详情组件的链接(<a [routerLink]="['/contact', contact.id]">Go to details</a>)。

    下面是组件截屏:

    Contact list

    当我们点击Go to detail链接,路由器会将我们导航到ContactDetailsComponent组件。导航路径中有一个id参数,让我们看看如何在详情组件中访问这个参数。

    打开src/app/contact-detail/contact-detail.component.ts文件,将它修改至如下形式:

    import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';
    import { ContactService } from '../contact.service';
    
    @Component({
      selector: 'app-contact-detail',
      templateUrl: './contact-detail.component.html',
      styleUrls: ['./contact-detail.component.css']
    })
    export class ContactDetailComponent implements OnInit {
      
      contact: any;
      constructor(private contactService: ContactService, private route: ActivatedRoute) { }
    
      ngOnInit() {
        this.route.paramMap.subscribe(params => {
        console.log(params.get('id'))
         this.contactService.getContact(params.get('id')).subscribe(c =>{
            console.log(c);
            this.contact = c;
        })   
        });
         
      }
    }
    

    我们在组件中注入了ContactServiceActivatedRoute,在钩子函数ngOnInit()中检索将从路由中传递过来的id属性,并使用它获取我们分配给contact对象的联系人详细信息。

    打开src/app/contact-detail/contact-detail.component.html文件,添加:

    <h1> Contact # {{contact.id}}</h1>
    <p>
      Name: {{contact.name}} 
    </p>
    <p>
     Email: {{contact.email}}
    </p>
    
    Contact details

    当我们第一次从127.0.0.1:4200/访问我们的应用时,路由出口不会渲染任何组件,因此让我们向路由数组中添加如下路由来将空路径重定向到contacts:

    {path: '', pathMatch: 'full', redirectTo: 'contacts'}  
    

    我们想匹配完全空的路径,所以我们将路由匹配策略指定为full.

    总结

    在本教程中,我们了解了如何使用Angular路由器向应用程序中添加路由和导航。我们了解了很多概念,例如路由出口,路由和路径,并且我们创建了一个demo来实际展示这些不同的概念。你可以在github上获取这些代码。

    关于本文
    作者:@Ahmed
    原文:https://www.smashingmagazine.com/2018/11/a-complete-guide-to-routing-in-angular/

    相关文章

      网友评论

          本文标题:(译)angular路由完全指南

          本文链接:https://www.haomeiwen.com/subject/csojkqtx.html