创建路由

1.首先安装 Angular Router。你可以通过运行以下任一操作来执行此操作:

yarn add @angular/router
# OR
npm i --save @angular/router

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

2.然后将 <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 路由,应用程序的根目录是 / 。

使用路由

要使用路由,我们需要在 AppModule 模块中,导入 RouterModule 。具体如下:

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

此时我们的路由还不能正常工作,因为我们还未配置应用程序路由的相关信息。RouterModule 对象为我们提供了两个静态的方法:forRoot() 和 forChild() 来配置路由信息。

RouterModule.forRoot()

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

// ...
import { Routes, RouterModule } from '@angular/router'; export const ROUTES: Routes = []; @NgModule({
imports: [
BrowserModule,
RouterModule.forRoot(ROUTES)
],
// ...
})
export class AppModule {}

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

RouterModule.forChild()

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

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

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

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router'; export const ROUTES: Routes = []; @NgModule({
imports: [
CommonModule,
RouterModule.forChild(ROUTES)
],
// ...
})
export class ChildModule {}

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

配置路由

我们定义的所有路由都是作为 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

显示路由

配置完路由信息后,下一步是使用一个名为 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 {}

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

其他路由配置

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

动态路由

如果路由始终是静态的,那没有多大的用处。例如 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/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);
}
}

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

子路由

实际上每个路由都支持子路由,假设在我们 /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 },
{ path: 'password', component: PasswordSettingsComponent }
]
}
]; @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路由

另一个很有用的路由功能是 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 路由的功能。

让我们创建一个 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)
],
})
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 的属性值,该字符串由三部分组成:

  • 需要导入模块的相对路径

  • # 分隔符

  • 导出模块类的名称

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

路由指令

除了 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 中设置的值。

友情提示:我们也可以将 routerLink 的属性值,改成数组形式,以便我们传递特定的路由信息

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

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

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 元素上。

最后,我们来简单介绍一下 Router API。

路由API

我们可以通过路由还提供的 API 实现与 routerLink 相同的功能。要使用 Router API,我们需要在组件类中注入 Router对象,具体如下:

import { Component } from '@angular/core';
import { Router } from '@angular/router'; @Component({
selector: 'app-root',
template: `
<div class="app">
<h3>Our app</h3>
<router-outlet></router-outlet>
</div>
`
})
export class AppComponent {
constructor(private router: Router) {}
}

组件类中注入的 router 对象中有一个 navigate() 方法,该方法支持的参数类型与 routerLink 指令一样,当调用该方法后,页面将会自动跳转到对应的路由地址。具体使用示例如下:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router'; @Component({
selector: 'app-root',
template: `
<div class="app">
<h3>Our app</h3>
<router-outlet></router-outlet>
</div>
`
})
export class AppComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
setTimeout(() => {
this.router.navigate(['/settings']);
}, 5000);
}
}

若以上代码成功运行,用户界面将在 5 秒后被重定向到 /settings 页面。这个方法非常有用,例如当检测到用户尚未登录时,自动重定向到登录页面。

另一个使用示例是演示页面跳转时如何传递数据,具体如下:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router'; @Component({
selector: 'app-root',
template: `
<div class="app">
<h3>Users</h3>
<div *ngFor="let user of users">
<user-component
[user]="user"
(select)="handleSelect($event)">
</user-component>
</div>
<router-outlet></router-outlet>
</div>
`
})
export class AppComponent implements OnInit {
users: Username[] = [
{ name: 'toddmotto', id: 0 },
{ name: 'travisbarker', id: 1 },
{ name: 'tomdelonge', id: 2 }
]; constructor(private router: Router) {} handleSelect(event) {
this.router.navigate(['/profile', event.name]);
}
}

Angular 路由的功能非常强大,既可以使用指令方式也可以使用命令式 API。

除了使用 navigate() 方法外还有没有其它方法可以实现页面导航?

Angular Router API 为我们提供了 navigate() 和 navigateByUrl() 方法来实现页面导航。那为什么会有两个不同的方法呢?

使用 router.navigateByUrl() 方法与直接改变地址栏上的 URL 地址一样,我们使用了一个新的 URL 地址。然而 router.navigate() 方法基于一系列输入参数,产生一个新的 URL 地址。为了更好的区分它们之间的差异,我们来看个例子,假设当前的 URL 地址是:

/inbox/11/message/22(popup:compose)

当我们调用 router.navigateByUrl('/inbox/33/message/44') 方法后,此时的 URL 地址将变成 /inbox/33/message/44。但如果我们是调用 router.navigate('/inbox/33/message/44') 方法,当前的 URL 地址将变成 /inbox/33/message/44(popup:compose) 。

转载自:

Angular 4.x 路由快速入门

Angular学习笔记—路由(转载)的更多相关文章

  1. angular学习笔记(三十一)-$location(2)

    之前已经介绍了$location服务的基本用法:angular学习笔记(三十一)-$location(1). 这篇是上一篇的进阶,介绍$location的配置,兼容各版本浏览器,等. *注意,这里介绍 ...

  2. angular学习笔记(三十一)-$location(1)

    本篇介绍angular中的$location服务的基本用法,下一篇介绍它的复杂的用法. $location服务的主要作用是用于获取当前url以及改变当前的url,并且存入历史记录. 一. 获取url的 ...

  3. angular学习笔记(三十)-指令(10)-require和controller

    本篇介绍指令的最后两个属性,require和controller 当一个指令需要和父元素指令进行通信的时候,它们就会用到这两个属性,什么意思还是要看栗子: html: <outer‐direct ...

  4. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

  5. angular学习笔记(三十)-指令(7)-compile和link(1)

    这篇主要讲解指令中的compile,以及它和link的微妙的关系. link函数在之前已经讲过了,而compile函数,它和link函数是不能共存的,如果定义了compile属性又定义link属性,那 ...

  6. angular学习笔记(三十)-指令(6)-transclude()方法(又称linker()方法)-模拟ng-repeat指令

    在angular学习笔记(三十)-指令(4)-transclude文章的末尾提到了,如果在指令中需要反复使用被嵌套的那一坨,需要使用transclude()方法. 在angular学习笔记(三十)-指 ...

  7. angular学习笔记(三十)-指令(5)-link

    这篇主要介绍angular指令中的link属性: link:function(scope,iEle,iAttrs,ctrl,linker){ .... } link属性值为一个函数,这个函数有五个参数 ...

  8. angular学习笔记(三十)-指令(2)-restrice,replace,template

    本篇主要讲解指令中的 restrict属性, replace属性, template属性 这三个属性 一. restrict: 字符串.定义指令在视图中的使用方式,一共有四种使用方式: 1. 元素: ...

  9. angular学习笔记(三十)-指令(1)-概述

    之前在 angular学习笔记(十九)-指令修改dom 里面已经简单的提到了angular中的指令,现在来详细的介绍 '指令' 一.指令的创建: dirAppModule.directive('dir ...

随机推荐

  1. [转]解决Access restriction: The type * is not accessible due to restrict

    我在eclipse使用org.omg下的东西的时候报此错误 我用的第一种方法解决了问题 转自:http://blog.sina.com.cn/s/blog_6714fba70100x6mz.html ...

  2. DMA—直接存储区访问

    本章参考资料:< STM32F4xx 中文参考手册> DMA 控制器章节.学习本章时,配合< STM32F4xx 中文参考手册> DMA 控制器章节一起阅读,效果会更佳,特别是 ...

  3. ubuntu设置静态ip地址

    每次设置都忘了之前怎么设置的,所以今天记录下来. 1. 找到文件并作如下修改: sudo vim /etc/network/interfaces 修改如下部分: auto eth0iface eth0 ...

  4. MapReduce实战(四)倒排索引的实现

    需求: 以上三个文件,用MapReduce进行处理,最终输出以下格式: hello c.txt-->2 b.txt-->2 a.txt-->3jerry c.txt-->1 b ...

  5. python笔记2-数据类型:字符串常用操作

    这次主要介绍字符串常用操作方法及例子 1.python字符串 在python中声明一个字符串,通常有三种方法:在它的两边加上单引号.双引号或者三引号,如下: name = 'hello' name1 ...

  6. 第一百四十一节,JavaScript,封装库--DOM加载

    JavaScript,封装库--DOM加载 DOM加载,跨浏览器封装DOM加载,当网页文档结构加载完毕后执行函数,不等待图片音频视频等文件加载完毕 /** dom_jia_zai()函数,DOM页面加 ...

  7. HTML5 选择前置摄像头,选择后置摄像头

    最近发现我写的都是乱七八糟的,觉得应该给大家带点福利,于是写了这篇 背景:最近想做个web应用,需要用到摄像头,但是发现默认一直是前置摄像头,拍照很麻烦,于是找了很多文章,居然没有人提到,只好FQ去找 ...

  8. Cross compile perl

    Alex Suykov had do some work for this purpose, and my compile script is based on her patch. Steps St ...

  9. 3D游戏引擎〇 開始

    游戏循环: 初始化:运行一些主要的初始化操作,如内存分配,资源获取.从磁盘载入数据等. 进入游戏循环:进入主游戏循环.用户不断地运行动作,知道退出主循环为止. 读取玩家输入:处理玩家输入,或将其存储到 ...

  10. JavaScript------字符串中各种方法

    参考“菜鸟教程” http://www.runoob.com/js/js-strings.html 1.search() var s = "Hello World"; alert( ...