填写这份《一分钟调查》,帮我们(开发组)做得更好!去填写Home

在单页面应用中使用 Angular 路由

Using Angular routes in a single-page application

本教程将介绍如何构建一个使用多个 Angular 路由的单页面应用 SPA。

This tutorial describes how you can build a single-page application, SPA that uses multiple Angular routes.

在 SPA 中,所有应用的所有功能都存在于同一个 HTML 页面中。当用户访问应用的各种特性时,浏览器只需渲染那些用户需要关心的部分,而不用重新加载页面。这种模式可以显著改善应用的用户体验。

In an SPA, all of your application's functions exist in a single HTML page. As users access your application's features, the browser needs to render only the parts that matter to the user, instead of loading a new page. This pattern can significantly improve your application's user exprience.

为了定义用户如何在应用中导航,你可以使用路由。你可以添加一些路由来定义用户如何从应用的某个部分导航到另一部分。你也可以配置一些路由来防范意外或未经授权的行为。

To define how users navigate through your application, you use routes. You can add routes to define how users navigate from one part of your application to another. You can also configure routes to guard against unexpected or unauthorized behavior.

要探索本教程的示例应用,请参阅现场演练 / 下载范例

To explore a sample app featuring the contents of this tutorial, see the现场演练 / 下载范例.

目标

Objectives

  • 将示例应用的各个特性组织到一些模块中。

    Organize a sample application's features into modules.

  • 定义如何导航到组件。

    Define how to navigate to a component.

  • 使用参数把信息传给组件。

    Pass information to a component using a parameter.

  • 通过嵌套多个路由来构造路由体系。

    Structure routes by nesting several routes.

  • 检查用户是否可以访问路由。

    Check whether users can access a route.

  • 控制该应用是否可以放弃未保存的更改。

    Control whether the application can discard unsaved changes.

  • 通过预先获取路由数据和惰性加载特性模块来提高性能。

    Improve performance by pre-fetching route data and lazy loading feature modules.

  • 需要特定的条件来加载组件。

    Require specific criteria to load components.

先决条件

Prerequisites

要完成本教程,你应该对这些概念有一个基本的了解:

To complete this tutorial, you should have a basic understanding of the following concepts:

你可能会发现英雄指南教程很有帮助,但它并不是必须的。

You might find the Tour of Heroes tutorial helpful, but it is not required.

创建一个示例应用

Create a sample application

使用 Angular CLI,创建一个新的应用angular-router-sample。这个应用程序有两个组件: crisis-listheroes-list

Using the Angular CLI, create a new application, angular-router-sample. This application will have two components: crisis-list and heroes-list.

  1. 创建一个新的 Angular 项目 angular-router-sample

    Create a new Angular project, angular-router-sample.

    ng new angular-router-sample
          
          ng new angular-router-sample
        

    当系统提示 Would you like to add Angular routing? 时,选择 N

    When prompted with Would you like to add Angular routing?, select N.

    当系统提示 Which stylesheet format would you like to use? 时,选择 CSS

    When prompted with Which stylesheet format would you like to use?, select CSS.

    一段时间后,一个新项目 angular-router-sample 就准备就绪了。

    After a few moments, a new project, angular-router-sample, is ready.

  2. 在终端上,导航到 angular-router-sample 目录。

    From your terminal, navigate to the angular-router-sample directory.

  3. 创建一个组件 crisis-list

    Create a component, crisis-list.

    ng generate component crisis-list
          
          ng generate component crisis-list
        
  4. 在你的代码编辑器中,找到文件 crisis-list.component.html 并用如下 HTML 替换占位符内容。

    In your code editor, locate the file, crisis-list.component.html and replace the placeholder content with the following HTML.

    <h3>CRISIS CENTER</h3> <p>Get your crisis here</p>
    src/app/crisis-list/crisis-list.component.html
          
          <h3>CRISIS CENTER</h3>
    <p>Get your crisis here</p>
        
  5. 创建第二个组件 heroes-list

    Create a second component, heroes-list.

    ng generate component heroes-list
          
          ng generate component heroes-list
        
  6. 在你的代码编辑器中,找到 heroes-list.component.html 文件,并用如下 HTML 替换占位符内容。

    In your code editor, locate the file, heroes-list.component.html and replace the placeholder content with the following HTML.

    <h3>HEROES</h3> <p>Get your heroes here</p>
    src/app/heroes-list/heroes-list.component.html
          
          <h3>HEROES</h3>
    <p>Get your heroes here</p>
        
  7. 在你的代码编辑器中,打开文件 app.component.html 并用如下 HTML 替换其内容。

    In your code editor, open the file, app.component.html and replace its contents with the following HTML.

    <h1>Angular Router Sample</h1> <app-crisis-list></app-crisis-list> <app-heroes-list></app-heroes-list>
    src/app/app.component.html
          
          <h1>Angular Router Sample</h1>
    <app-crisis-list></app-crisis-list>
    <app-heroes-list></app-heroes-list>
        
  8. 运行 ng serve 来验证新应用是否正常运行。

    Verify that your new application runs as expected by running the ng serve command.

    ng serve
          
          ng serve
        
  9. 打开浏览器访问 http://localhost:4200

    Open a browser to http://localhost:4200.

    你会看到一个网页,它由一个标题和两个组件的 HTML 组成。

    You should see a single web page, consisting of a title and the HTML of your two components.

@angular/router 导入 RouterModule

Import RouterModule from @angular/router

路由允许你根据 URL 路径显示应用的特定视图。要把这个功能添加到你的示例应用中,你需要更新 app.module.ts 文件以使用模块 RouterModule。你可以从 @angular/router 导入该模块。

Routing allows you to display specific views of your application depending on the URL path. To add this functionality to your sample application, you need to update the app.module.ts file to use the module, RouterModule. You import this module from @angular/router.

  1. 在代码编辑器中,打开 app.module.ts 文件。

    From your code editor, open the app.module.ts file.

  2. 添加如下 import 语句。

    Add the following import statement.

    import { RouterModule } from '@angular/router';
    src/app/app.module.ts
          
          import { RouterModule } from '@angular/router';
        

定义你的各个路由

Define your routes

在本节中,你将定义两个路由:

In this section, you'll define two routes:

  • 路由 /crisis-center 用来打开 crisis-center 组件。

    The route /crisis-center opens the crisis-center component.

  • 路由 /heroes-list 用来打开 heroes-list 组件。

    The route /heroes-list opens the heroes-list component.

路由定义是一个 JavaScript 对象。每个路由通常都有两个属性。第一个属性 path 是一个字符串,它指定路由的 URL 路径。第二个属性 component 是组件类,它指定应用要为该路由显示哪个组件。

A route definition is a JavaScript object. Each route typically has two propteries. The first property, path, is a string that specifies the URL path for the route. The second property, component, is a string that specifies what component your application should display for that path.

  1. 在代码编辑器中,打开 app.module.ts 文件。

    From your code editor, open the app.module.ts file.

  2. 找到 @NgModule() 部分。

    Locate the @NgModule() section.

  3. 用如下代码替换这部分的 imports 数组。

    Replace the imports array in that section with the following.

    imports: [ BrowserModule, RouterModule.forRoot([ {path: 'crisis-list', component: CrisisListComponent}, {path: 'heroes-list', component: HeroesListComponent}, ]), ],
    src/app/app.module.ts
          
          imports: [
      BrowserModule,
      RouterModule.forRoot([
        {path: 'crisis-list', component: CrisisListComponent},
        {path: 'heroes-list', component: HeroesListComponent},
      ]),
    ],
        

这段代码把 RouterModule 添加到了 imports 数组中。接下来,该代码使用 RouterModuleforRoot() 方法来定义你的两个路由。该方法接受一个 JavaScript 对象数组,每个对象定义一个路由的属性。forRoot() 方法确保你的应用只会实例化一个 RouterModule。有关更多信息,请参阅单例服务

This code adds the RouterModule to the imports array. Next, the code uses the forRoot() method of the RouterModule to define your two routes. This method takes an array of JavaScript objects, with each object defining the proprties of a route. The forRoot() method ensures that your application only instantiates one RouterModule. For more information, see Singleton Services.

更新你的组件以添加 router-outlet

Update your component with router-outlet

此刻,你已经为应用定义了两个路由。但是,你的应用仍然在你的 app.component.html 模板中硬编码着 crisis-listheroes-list 组件。为了让你的路由正常工作,需要更新模板,以便根据 URL 路径动态加载一个组件。

At this point, you have defined two routes for your application. However, your application still has both the crisis-list and heroes-list components hard-coded in your app.component.html template. For your routes to work, you need to update your template to dynamically load a component based on the URL path.

要实现这个功能,你就可以把 router-outlet 指令添加到模板文件中。

To implement this functionality, you add the router-outlet directive to your template file.

  1. 在代码编辑器中,打开 app.component.html 文件。

    From your code editor, open the app.component.html file.

  2. 删除下面这几行。

    Delete the following lines.

    <app-crisis-list></app-crisis-list> <app-heroes-list></app-heroes-list>
    src/app/app.component.html
          
          <app-crisis-list></app-crisis-list>
    <app-heroes-list></app-heroes-list>
        
  3. 添加 router-outlet 指令。

    Add the router-outlet directive.

    src/app/app.component.html
          
          <router-outlet></router-outlet>
        

在浏览器中查看更新后的应用。你应该只看到应用标题。要查看 crisis-list 组件,就要把 crisis-list 添加到浏览器地址栏的路径末尾。例如:

View your updated application in your browser. You should see only the application title. To view the crisis-list component, add crisis-list to the end of the path in your browser's address bar. For example:

http://localhost:4200/crisis-list
      
      http://localhost:4200/crisis-list
    

注意,crisis-list 组件会显示出来。Angular 正在使用你定义的路由来动态加载组件。你可以用同样的方法加载 heroes-list 组件:

Notice that the crisis-list component displays. Angular is using the route you defined to dynamically load the component. You can load the heroes-list component the same way:

http://localhost:4200/heroes-list
      
      http://localhost:4200/heroes-list
    

用 UI 元素控制导航

Control navigation with UI elements

目前,你的应用支持两种路由。但是目前使用这些路由的唯一方法是让用户在浏览器的地址栏中手动输入路径。在本节中,你要添加两个链接,用户可以单击它们在 heroes-listcrisis-list 组件之间导航。你还会添加一些 CSS 样式。虽然这些样式不是必需的,但它们可以让你更容易的识别出当前显示的组件的链接。你将在下一节中添加此功能。

Currently, your application supports two routes. However, the only way to use those routes is for the user to manually type the path in the browser's address bar. In this section, you'll add two links that users can click to navigate between the heroes-list and crisis-list components. You'll also add some CSS styles. While these styles are not required, they make it easier to identify the link for the currently-displayed component. You'll add that functionality in the next section.

  1. 打开 app.component.html 文件,在标题下方添加以下 HTML。

    Open the app.component.html file and add the following HTML below the title.

    <nav> <a class="button" routerLink="/crisis-list">Crisis Center</a> | <a class="button" routerLink="/heroes-list">Heroes</a> </nav>
    src/app/app.component.html
          
          <nav>
      <a class="button" routerLink="/crisis-list">Crisis Center</a> |
      <a class="button" routerLink="/heroes-list">Heroes</a>
    </nav>
        

    这个 HTML 使用了 Angular 指令 routerLink。该指令将你定义的路由连接到模板文件中。

    This HTML uses an Angular directive, routerLink. This directive connects the routes you defined to your template files.

  2. 打开 app.component.css 文件并添加如下样式。

    Open the app.component.css file and add the following styles.

    .button { box-shadow: inset 0px 1px 0px 0px #ffffff; background: linear-gradient(to bottom, #ffffff 5%, #f6f6f6 100%); background-color: #ffffff; border-radius: 6px; border: 1px solid #dcdcdc; display: inline-block; cursor: pointer; color: #666666; font-family: Arial; font-size: 15px; font-weight: bold; padding: 6px 24px; text-decoration: none; text-shadow: 0px 1px 0px #ffffff; outline: 0; } .activebutton { box-shadow: inset 0px 1px 0px 0px #dcecfb; background: linear-gradient(to bottom, #bddbfa 5%, #80b5ea 100%); background-color: #bddbfa; border-radius: 6px; border: 1px solid #84bbf3; display: inline-block; cursor: pointer; color: #ffffff; font-family: Arial; font-size: 15px; font-weight: bold; padding: 6px 24px; text-decoration: none; text-shadow: 0px 1px 0px #528ecc; outline: 0; }
    src/app/app.component.css
          
          .button {
        box-shadow: inset 0px 1px 0px 0px #ffffff;
        background: linear-gradient(to bottom, #ffffff 5%, #f6f6f6 100%);
        background-color: #ffffff;
        border-radius: 6px;
        border: 1px solid #dcdcdc;
        display: inline-block;
        cursor: pointer;
        color: #666666;
        font-family: Arial;
        font-size: 15px;
        font-weight: bold;
        padding: 6px 24px;
        text-decoration: none;
        text-shadow: 0px 1px 0px #ffffff;
        outline: 0;
    }
    .activebutton {
        box-shadow: inset 0px 1px 0px 0px #dcecfb;
        background: linear-gradient(to bottom, #bddbfa 5%, #80b5ea 100%);
        background-color: #bddbfa;
        border-radius: 6px;
        border: 1px solid #84bbf3;
        display: inline-block;
        cursor: pointer;
        color: #ffffff;
        font-family: Arial;
        font-size: 15px;
        font-weight: bold;
        padding: 6px 24px;
        text-decoration: none;
        text-shadow: 0px 1px 0px #528ecc;
        outline: 0;
    }
        

如果你在浏览器中查看应用,你会看到这两个链接。单击某个链接时,会出现相应的组件。

If you view your application in the browser, you should see these two links. When you click on a link, the corresponding component appears.

标出活动路由

Identify the active route

虽然用户可以使用上一节中添加的链接来浏览你的应用,但他们并没有简单的方法来确定活动路由是什么。可以使用 Angular 的 routerLinkActive 指令添加这个功能。

While users can navigate your application using the links you added in the previous section, they don't have an easy way to identify what the active route is. You can add this functionality using Angular's routerLinkActive directive.

  1. 在代码编辑器中,打开 app.component.html 文件。

    From your code editor, open the app.component.html file.

  2. 更新 a 标签以包含 routerLinkActive 指令。

    Update the anchor tags to include the routerLinkActive directive.

    <nav> <a class="button" routerLink="/crisis-list" routerLinkActive="activebutton">Crisis Center</a> | <a class="button" routerLink="/heroes-list" routerLinkActive="activebutton">Heroes</a> </nav>
    src/app/app.component.html
          
          <nav>
      <a class="button" routerLink="/crisis-list" routerLinkActive="activebutton">Crisis Center</a> |
      <a class="button" routerLink="/heroes-list" routerLinkActive="activebutton">Heroes</a>
    </nav>
        

再次查看你的申请表。单击其中一个按钮时,该按钮的样式会自动更新,并为该用户标出该活动组件。通过添加 routerLinkActive 指令,可以通知你的应用把一个特定的 CSS 类应用到当前的活动路由中。在本教程中,这个 CSS 类是 activebutton,但你可以使用任何想要的类。

View your application again. As you click one of the buttons, the style for that button updates automatically, identifying the active component to the user. By adding the routerLinkActive directive, you inform your application to apply a specific CSS class to the active route. In this tutorial, that CSS class is activebutton, but you could use any class that you want.

添加一个重定向

Adding a redirect

在本教程的这一步中,你将添加一个重定向路由来把用户导向 /heroes-list 组件。

In this step of the tutorial, you add a route that redirects the user to display the /heroes-list component.

  1. 在代码编辑器中,打开 app.module.ts 文件。

    From your code editor, open the app.module.ts file.

  2. imports 数组中,按如下所示更新 RouterModule 部分。

    In the imports array, update the RouterModule section as follows.

    imports: [ BrowserModule, RouterModule.forRoot([ {path: 'crisis-list', component: CrisisListComponent}, {path: 'heroes-list', component: HeroesListComponent}, {path: '', redirectTo: '/heroes-list', pathMatch: 'full'}, ]), ],
    src/app/app.module.ts
          
          imports: [
      BrowserModule,
      RouterModule.forRoot([
        {path: 'crisis-list', component: CrisisListComponent},
        {path: 'heroes-list', component: HeroesListComponent},
        {path: '', redirectTo: '/heroes-list', pathMatch: 'full'},
      ]),
    ],
        

    注意这个新路由使用一个空字符串作为它的路径。另外,它还把 component 属性替换成了这两个新属性:

    Notice that this new route uses an empty string as its path. In addition, it replaces the component property with two new ones:

    • redirectTo。这个属性指示 Angular 从空路径重定向到 heroes-list 路径。

      redirectTo. This property instructs Angular to redirect from an empty path to the heroes-list path.

    • pathMatch。这个属性指示 Angular 要如何匹配 URL。对于本教程,你应该把这个属性设置为 full。当路径为空字符串时,建议使用此策略。有关此属性的更多信息,请参阅 Route API 文档

      pathMatch. This property instructs Angular on how much of the URL to match. For this tutorial, you should set this property to full. This strategy is recommended when you have an empty string for a path. For more information about this property, see the Route API documentation.

现在,当你打开应用时,它会默认显示 heroes-list 组件。

Now when you open your application, it displays the heroes-list component by default.

添加 404 页面

Adding a 404 page

用户可以尝试访问你尚未定义的路由。为了解决这个问题,最佳做法是显示一个 404 页面。在本节中,你将创建一个 404 页面,并更新路由配置,以便为任何未指定的路由显示该页面。

It is possible for a user to try to access a route that you have not defined. To account for this behavior, a best practice is to display a 404 page. In this section, you'll create a 404 page and update your route configuration to show that page for any unspecified routes.

  1. 在终端上,创建一个新的组件 PageNotFound

    From the terminal, create a new component, PageNotFound.

    ng generate component page-not-found
          
          ng generate component page-not-found
        
  2. 在代码编辑器中,打开 page-not-found.component.html 文件并用下面的 HTML 替换它的内容。

    From your code editor, open the page-not-found.component.html file and replace its contents with the following HTML.

    <h2>Page Not Found</h2> <p>We couldn't find that page! Not even with x-ray vision.</p>
    src/app/page-not-found/page-not-found.component.html
          
          <h2>Page Not Found</h2>
    <p>We couldn't find that page! Not even with x-ray vision.</p>
        
  3. 打开 app.module.ts 文件。在其 imports 数组中,按如下所示更新 RouterModule 部分的内容。

    Open the app.module.ts file. In the imports array, update the RouterModule section as follows.

    imports: [ BrowserModule, RouterModule.forRoot([ {path: 'crisis-list', component: CrisisListComponent}, {path: 'heroes-list', component: HeroesListComponent}, {path: '', redirectTo: '/heroes-list', pathMatch: 'full'}, {path: '**', component: PageNotFoundComponent} ]), ],
    src/app/app.module.ts
          
          imports: [
      BrowserModule,
      RouterModule.forRoot([
        {path: 'crisis-list', component: CrisisListComponent},
        {path: 'heroes-list', component: HeroesListComponent},
        {path: '', redirectTo: '/heroes-list', pathMatch: 'full'},
        {path: '**', component: PageNotFoundComponent}
      ]),
    ],
        

    新路由使用路径 **。这个路径是 Angular 表示通配符路由的方式。任何与你配置中的路由都不匹配的路由都会使用这个路由。

    The new route uses a path, **. This path is how Angular identifies a wildcard route. Any route that does not match an existing route in your configuration will use this route.

    请注意,通配符路由要放在数组的末尾。路由的顺序很重要,因为 Angular 会按顺序应用路由并使用所找到的第一个匹配项。

    Notice that the wildcard route is placed at the end of the array. The order of your routes is important, as Angular applies routes in order and uses the first match it finds.

尝试导航到应用中不存在的路由,比如 http://localhost:4200/powers。此路由与 app.module.ts 文件中定义的所有内容都不匹配。但是,由于你定义了一个通配符路由,该应用会自动显示你的 PageNotFound 组件。

Try navigating to a non-existing route on your application, such as http://localhost:4200/powers. This route doesn't match anything defined in your app.module.ts file. However, because you defined a wildcard route, the application automatically displays your PageNotFound component.

下一步

Next steps

你已经有了一个基本的应用程序,它使用 Angular 的路由功能来根据 URL 地址改变用户可以看到的组件。你还扩展了这些特性,以包含一个重定向,以及一个用来显示自定义 404 页面的通配符路由。

At this point, you have a basic application that uses Angular's routing feature to change what components the user can see based on the URL address. You have extended these features to include a redirect, as well as a wildcard route to display a custom 404 page.

有关路由的更多信息,请参阅以下主题:

For more information about routing, see the following topics: