Angular 4.x 路由快速入门

路由是 Angular 应用程序的核心,它加载与所请求路由相关联的组件,以及获取特定路由的相关数据。这允许我们通过控制不同的路由,获取不同的数据,从而渲染不同的页面。

接下来我们将按照以下目录的内容,介绍 Angular 的路由。具体目录如下:

Installing the router

npm install --save @angular/router

以上命令执行后,将会自动下载 @angular/router 模块到node_modules文件夹中。

Base href

路由需要根据这个来确定应用程序的根目录

我们需要做的最后一件事,是将 <base> 标签添加到我们的 index.html文件中。例如,当我们转到 http://example.com/page1时,如果我们没有定义应用程序的基础路径,路由将无法知道我们的应用的托管地址是 http://example.com还是 http://example.com/page1

这件事操作起来很简单,只需打开项目中的 index.html文件,添加相应的 <base>标签,具体如下:

<!doctype html>
<html>
  <head>
    <base href="/">
    <title>Application</title>
  </head>
  <body>
    <app-root></app-root>
  </body>
</html>

以上配置信息告诉 Angular 路由,应用程序的根目录是 /

使用路由

RouterModule.forRoot()

RouterModule.forRoot()方法用于在主模块中定义主要的路由信息,通过调用该方法使得我们的主模块可以访问路由模块中定义的所有指令。接下来我们来看一下如何使用forRoot()

1.在模块中引入主路由模块

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from '@angular/router';
import { AppComponent } from './app.component';

@NgModule({
  imports: [
    BrowserModule,
    AppRoutingModule           //导入主路由模块
  ],
  bootstrap: [
    AppComponent
  ],
  declarations: [
    AppComponent
  ]
})
export class AppModule {}   //主模块

2.定义主路由模块

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; // CLI imports router

const routes: Routes = [];       //配置路由内容

// 配置 NgModule imports and exports
@NgModule({
  imports: [RouterModule.forRoot(routes)],     //主路由模块使用forRoot加载路由
  exports: [RouterModule]
})
export class AppRoutingModule { }   //主路由模块

我们通过使用const 定义路由的配置信息,然后把它作为参数调用 RouterModule.forRoot() 方法,而不是直接使用 RouterModule.forRoot([...])这种方式,这样做的好处是方便我们在需要的时候导出 ROUTES 到其它模块中。

RouterModule.forChild()

RouterModule.forChild() 与 Router.forRoot() 方法类似,但它只能应用在特性模块中。

友情提示:根模块中使用 forRoot(),子模块中使用 forChild()

这个功能非常强大,因为我们不必在一个地方(我们的主模块)定义所有路由信息。反之,我们可以在特性模块中定义模块特有的路由信息,并在必要的时候将它们导入我们主模块。RouterModule.forChild() 的使用方法如下:

1.主模块引入子路由模块

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';

@NgModule({
  imports: [
    BrowserModule,
    ChildModule,                 //导入子路由模块
    AppRoutingModule           //导入主路由模块
  ],
  bootstrap: [
    AppComponent
  ],
  declarations: [
    AppComponent
  ]
})
export class AppModule {}
每个路由模块都会根据导入的顺序把自己的路由配置追加进去。 如果你先列出了 AppRoutingModule,那么通配符路由就会被注册在“ChildModule”路由之前。 通配符路由(它匹配任意URL)将会拦截住每一个到“英雄管理”路由的导航,因此事实上屏蔽了所有“ChildModule”路由。

注意:建议子路由模块在主路由模块之前声明,这样优先以子路由为准

2.定义子路由模块

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';

export const ROUTES: Routes = [];

@NgModule({
  imports: [
    RouterModule.forChild(ROUTES)   //特性模块中使用forChild加载路由跑;配置
  ],
 exports: [
    RouterModule            //导出依赖
  ]
})
export class ChildModule {}   //特性模块,即子模块

通过以上示例,我们知道在主模块和特性模块中,路由配置对象的类型是一样的,区别只是主模块和特性模块中需调用不同的方法,来配置模块路由。接下来我们来介绍一下如何配置 ROUTES 对象。

Configuring a route

我们定义的所有路由都是作为 ROUTES 数组中的对象。首先,为我们的主页定义一个路由:

import { Routes, RouterModule } from '@angular/router';

import { HomeComponent } from './home/home.component';

export const ROUTES: Routes = [
  { path: '', component: HomeComponent }
];

@NgModule({
  imports: [
    BrowserModule,
    RouterModule.forRoot(ROUTES)
  ],
  // ...
})
export class AppModule {}

示例中我们通过 path属性定义路由的匹配路径,而component属性用于定义路由匹配时需要加载的组件。

友情提示:我们使用 path: '' 来匹配空的路径,例如:https://yourdomain.com

Displaying routes

配置完路由信息后,下一步是使用一个名为router-outlet的指令告诉 Angular 在哪里加载组件。当 Angular 路由匹配到响应路径,并成功找到需要加载的组件时,它将动态创建对应的组件,并将其作为兄弟元素,插入到router-outlet元素之后。

在我们 AppComponent组件中,我们可以在任意位置插入 router-outlet指令:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div class="app">
      <h3>Our app</h3>
      <router-outlet></router-outlet>
    </div>
  `
})
export class AppComponent {}

我们现在已经建立了应用程序的主路由,我们可以进一步了解路由的其它配置选项。

Further configuration

到目前为止我们已经介绍的内容只是一个开始 ,接下来我们来看看其它一些选项和功能。

Dynamic routes

如果路由始终是静态的,那没有多大的用处。例如path: ''是加载我们 HomeComponent组件的静态路由。我们将介绍动态路由,基于动态路由我们可以根据不同的路由参数,渲染不同的页面。

例如,如果我们想要在个人资料页面根据不同的用户名显示不同的用户信息,我们可以使用以下方式定义路由:

import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';

export const ROUTES: Routes = [
  { path: '', component: HomeComponent },
  { path: '/profile/:username', component: ProfileComponent }
];

这里的关键点是 : ,它告诉 Angular 路由,:username是路由参数,而不是 URL 中实际的部分。

可以匹配/profile/zhangsan 、也可以匹配/profile/lisi

友情提示:如果没有使用 :,它将作为静态路由,仅匹配 /profile/username路径

现在我们已经建立一个动态路由,此时最重要的事情就是如何获取路由参数。要访问当前路由的相关信息,我们需要先从 @angular/router模块中导入 ActivatedRoute,然后在组件类的构造函数中注入该对象,最后通过订阅该对象的params 属性,来获取路由参数,具体示例如下:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'profile-page',
  template: `
    <div class="profile">
      <h3>{{ username }}</h3>
    </div>
  `
})
export class SettingsComponent implements OnInit {
  username: string;
  constructor(private route: ActivatedRoute) {}
  ngOnInit() {
    this.route.params.subscribe((params) => this.username = params.username);
  }
}

介绍完动态路由,我们来探讨一下如何创建 child routes

嵌套路由

实际上每个路由都支持子路由,假设在我们 /settings 设置页面下有 /settings/profile/settings/password两个页面,分别表示个人资料页和修改密码页。

我们可能希望我们的/ settings页面拥有自己的组件,然后在设置页面组件中显示/ settings/profile/ settings/password页面。我们可以这样做:

import { SettingsComponent } from './settings/settings.component';
import { ProfileSettingsComponent } from './settings/profile/profile.component';
import { PasswordSettingsComponent } from './settings/password/password.component';

export const ROUTES: Routes = [
  { 
    path: 'settings', 
    component: SettingsComponent,    //定义父页面
    children: [
      { path: 'profile', component: ProfileSettingsComponent },// 定义子页面profile
      { path: 'password', component: PasswordSettingsComponent }// 定义子页面password
    ]
  }
];

@NgModule({
  imports: [
    BrowserModule,
    RouterModule.forRoot(ROUTES)
  ],
})
export class AppModule {}

在这里,我们在 setttings路由中定义了两个子路由,它们将继承父路由的路径,因此修改密码页面的路由匹配地址是/settings/password,依此类推。

接下来,我们需要做的最后一件事是在我们的 SettingsComponent组件中添加router-outlet指令,因为我们要在设置页面中呈现子路由。如果我们没有在SettingsComponent组件中添加 router-outlet 指令,尽管 /settings/password匹配修改密码页面的路由地址,但修改密码页面将无法正常显示。具体代码如下:

import { Component } from '@angular/core';

@Component({
  selector: 'settings-page',
  template: `
    <div class="settings">
    <!-- 伪码,定义父组件的页面头部 -->
      <settings-header></settings-header>
       <!-- 伪码,定义父组件的页面边栏 -->
      <settings-sidebar></settings-sidebar>

	<!-- 定义子组件显示的位置 -->
      <router-outlet></router-outlet>  
    </div>
  `
})
export class SettingsComponent {}

Component-less routes

另一个很有用的路由功能是 component-less 路由。使用 component-less路由允许我们将路由组合在一起,并让它们共享路由配置信息和 outlet

例如,我们可以定义setttings 路由而不需要使用 SettingsComponent组件:

import { ProfileSettingsComponent } from './settings/profile/profile.component';
import { PasswordSettingsComponent } from './settings/password/password.component';

export const ROUTES: Routes = [
  {
    path: 'settings',
    children: [
      { path: 'profile', component: ProfileSettingsComponent },
      { path: 'password', component: PasswordSettingsComponent }
    ]
  }
];

@NgModule({
  imports: [
    BrowserModule,
    RouterModule.forRoot(ROUTES)
  ],
})
export class AppModule {}

此时,/settings/profile/settings/password 路由定义的内容,将显示在 AppComponent组件的router-outlet元素中。

不清楚 component-less的真正作用,我的理解是共享一段配置而已,抽出公共部分,避免冗余的配置,少些几个/settings,内容完全等价于《Configuring a route》章节内容,理论上应该和子路由扯不上关系。

lazy load (延迟加载子模块)

我们也可以告诉路由从另一个模块中获取子路由。这将我们谈论的两个想法联系在一起 - 我们可以指定另一个模块中定义的子路由,以及通过将这些子路由设置到特定的路径下,来充分利用 component-less 路由的功能。

让我们创建一个SettingsModule 模块,用来保存所有 setttings 相关的路由信息:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';

export const ROUTES: Routes = [
  {
    path: '',
    component: SettingsComponent,
    children: [
      { path: 'profile', component: ProfileSettingsComponent },
      { path: 'password', component: PasswordSettingsComponent }
    ]
  }
];

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(ROUTES)   //子模块使用forChild加载配置
  ],
})
export class SettingsModule {}     //子模块

需要注意的是,在 SettingsModule 模块中我们使用 forChild() 方法,因为 SettingsModule 不是我们应用的主模块。

另一个主要的区别是我们将SettingsModule 模块的主路径设置为空路径 ('')。因为如果我们路径设置为/settings ,它将匹配/settings/settings ,很明显这不是我们想要的结果。通过指定一个空的路径,它就会匹配/settings路径,这就是我们想要的结果。

那么 /settings 路由信息,需要在哪里配置?答案是在 AppModule 中。这时我们就需要用到loadChildren 属性,具体如下:

export const ROUTES: Routes = [
  {
    path: 'settings',
    loadChildren: './settings/settings.module#SettingsModule'   //延迟子模块中的路由
  }
];

@NgModule({
  imports: [
    BrowserModule,
    RouterModule.forRoot(ROUTES) 
  ],
  // ...
})
export class AppModule {}    //主模块

需要注意的是,我们没有将 SettingsModule导入到我们的 AppModule 中,而是通过 loadChildren属性,告诉 Angular 路由依据 loadChildren 属性配置的路径去加载 SettingsModule模块。这就是模块懒加载功能的具体应用,当用户访问/settings/**路径的时候,才会加载对应的 SettingsModule模块,这减少了应用启动时加载资源的大小。

另外我们传递一个字符串作为 loadChildren 的属性值,该字符串由三部分组成:

  • 需要导入模块的相对路径 ./settings/settings.module
  • # 分隔符 #
  • 导出模块类的名称 SettingsModule

了解完路由的一些高级选项和功能,接下来我们来介绍路由指令。

Router Directives

除了 router-outlet 指令,路由模块中还提供了一些其它指令。让我们来看看它们如何与我们之前介绍的内容结合使用。

routerLink

主要作用是避免页面重新加载,实现局部刷新

为了让我们链接到已设置的路由,我们需要使用 routerLink指令,具体示例如下:

<nav>
  <a routerLink="/">Home</a>
  <a routerLink="/settings/password">Change password</a>
  <a routerLink="/settings/profile">Profile Settings</a>
</nav>

当我们点击以上的任意链接时,页面不会被重新加载。反之,我们的路径将在 URL 地址栏中显示,随后进行后续视图更新,以匹配 routerLink 中设置的值。

如果我们想要链接到动态的路由地址,且该地址有一个 username的路由变量,则我们可以按照以下方式配置routerLink对应的属性值:

<a [routerLink]="['/profile', username]">
  Go to {{ username }}'s profile.
</a>

如果username的值为zhangsan,那么实际生成的链接为/profile/zhangsan

routerLinkActive

在实际开发中,我们需要让用户知道哪个路由处于激活状态,通常情况下我们通过向激活的链接添加一个 class 来实现该功能。为了解决上述问题,Angular 路由模块为我们提供了routerLinkActive指令,该指令的使用示例如下:

<nav>
  <a routerLink="/settings" routerLinkActive="active">Home</a>
  <a routerLink="/settings/password" routerLinkActive="active">Change password</a>
  <a routerLink="/settings/profile" routerLinkActive="active">Profile Settings</a>
</nav>

通过使用 routerLinkActive指令,当a 元素对应的路由处于激活状态时,active样式将会自动添加到 a元素上。

navigate()和navigateByUrl()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值