在用户使用应用程序时,Angular的路由器能让用户从一个视图导航到另一个视图。
概览
例子
浏览器具有我们熟悉的导航模式:
- 在地址栏输入URL,浏览器就会导航到相应的页面。
- 在页面中点击链接,浏览器就会导航到一个新页面。
- 点击浏览器的前进和后退按钮,浏览器就会在你的浏览历史中向前或向后导航。
Angular的Router借鉴了这个模型。把浏览器中的URL看做一个操作指南, 据此导航到一个由客户端生成的视图,并可以把参数传给支撑视图的相应组件,帮它决定具体该展现哪些内容。
开发人员为页面中的链接绑定一个路由,这样,当用户点击链接时,就会导航到应用中相应的视图。 当用户点击按钮、从下拉框中选取,或响应来自任何地方的事件时,开发人员也可以在代码控制下进行导航。 路由器还在浏览器的历史日志中记录下这些活动,这样浏览器的前进和后退按钮也能照常工作。
说明
- 路由是实现 SPA(单页应用程序) 的基础设施。
- 作用:让用户从一个视图导航到另一个视图。
- 路由是:URL 和 组件的对应规则。
- 使用:HTML5风格(history.pushState)的导航。
- 支持:重定向(可以默认调整活动页面)、路由高亮(会让当前点击的路由有高亮的效果)、通配符路由(配置一些有用的路由)、路由参数(通过路由参数来区分不同的新闻详情页)、子路由、路由模块(当路由比较复杂,分为一个模块)、路由守卫、异步路由等。
使用
-
在index.html中设置
。 -
导入
RouterModule
模块。 -
配置路由规则
appRoutes
。 -
将
RouterModule.forRoot(appRoutes)
模块配置在根模块中。 -
使用
指定路由出口。 -
使用
routerLink=”/home”
指定导航链接。代码演示
index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>MyAppr</title> // 1. 一定要检查是不是有这句话 这个有/ 记得在之后的 appRoutes 里面不要加/ <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root></app-root> </body> </html>
创建模块
$ ng g c home
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; // 2.. 导入路由模块 import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './home/home.component'; // 3. 配置路由规则 const appRoutes: Routes = [ { path: 'home', component: HomeComponent } ] @NgModule({ declarations: [ AppComponent, HomeComponent ], imports: [ BrowserModule, // 4. 配置路由模块,做为跟模块的依赖项 RouterModule.forRoot(appRoutes) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
- 导入路由模块
- 配置路由规则
- 配置路由模块,做为跟模块的依赖项
app.component.html
<h1>路由</h1> <!-- 5. 指定路由的出口 --> <router-outlet>home</router-outlet>
打开
http://localhost:4200/home
可以看到页面会显示home组件中的内容。<h1>路由</h1> <!-- 5 指定路由出口 --> <router-outlet></router-outlet> <!-- 6 指定导航链接 记得加/--> <a routerLink="/home">首页</a>
这样就可以更具点击首页进行跳转了。 页面内容以及展示出来,导航的地址也已经进行改变。
forRoot的说明
- 问题说明:服务应该是单例的,某些场景下会造成服务多次注册,破坏服务的单例特性。
- 比如:路由懒加载的情况。
- 解决方式:使用模块的
forRoot()
方法导入模块。 - RouterModule的
forRoot()
保证项目中只有一个Router服务。
路由配置
默认路由
路由跳转
通配符路由
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
const appRoutes: Routes = [
// 默认路由 -- 一般放在最前面
{ path:'', redirectTo: '/home', pathMatch: 'full'},
// 路由跳转
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
// 通配符路由 -- 一般放在最后面
{ path: '**', component: NotfoundComponent }
]
@NgModule({
.....
})
export class AppModule { }
编程式导航
notfound.component.html
<p>
对不起,您访问的页面不存在。
</p>
<p>
在s之后,返回首页。
</p>
notfound.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-notfound',
templateUrl: './notfound.component.html',
styleUrls: ['./notfound.component.css']
})
export class NotfoundComponent implements OnInit {
constructor(private router: Router) { }
time = 5;
ngOnInit() {
const timeId = setInterval(() => {
this.time--
console.log(this.time)
if( this.time === 0) {
clearInterval(timeId)
this.router.navigate(['/home'])
}
},1000)
}
}
路由参数
加入有两个列,一列是导航菜单new标题列表,另一列是new相对应的详情。路径会进行相应的改变。
案例: 笨蛋写法
创建3个组件
$ ng g c new1
$ ng g c new2
$ ng g c new3
app.component.ts
import .....
............
const appRoutes: Routes = [
{ path:'', redirectTo: '/home', pathMatch: 'full'},
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'new1', component: New1Component },
{ path: 'new2', component: New2Component },
{ path: 'new3', component: New3Component },
{ path: '**', component: NotfoundComponent }
]
@NgModule({
...
})
export class AppModule { }
home.component.html
<router-outlet></router-outlet>
<div>
<ul>
<li><a routerLink="/new1">new1</a></li>
<li><a routerLink="/new2">new2</a></li>
<li><a routerLink="/new3">new3</a></li>
</ul>
</div>
案例: 路由参数
创建子组件
$ ng g c new
app.component.ts
import .....
............
const appRoutes: Routes = [
{ path:'', redirectTo: '/home', pathMatch: 'full'},
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'new/:id', component: NewComponent },
{ path: '**', component: NotfoundComponent }
]
@NgModule({
...
})
export class AppModule { }
在
path: 'new/:id',
中:id
表示的是路由参数可以匹配的路径是
1. /new/1 2. /new/2 3. /new/3不可以匹配的路径是
- /new 2
- /new/2/info
app.component.html
<!-- 5 指定路由出口 -->
<router-outlet></router-outlet>
<!-- 6 指定导航链接 -->
<a routerLink="/home">首页</a>
<br>
<a routerLink="/about">About</a>
<br>
<div>
<ul>
<li><a routerLink="/new/1">new1</a></li>
<li><a routerLink="/new/2">new2</a></li>
</ul>
</div>
new.component.html
<h2></h2>
<p>
新闻详情 -
</p>
new.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-new',
templateUrl: './new.component.html',
styleUrls: ['./new.component.css']
})
export class NewComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
news = [
{ id:1, name:'1', desc: 'new1xxxxxxxxxxx'},
{ id:2, name:'2', desc: 'new2xxxxxxxxxxx'},
{ id:3, name:'3', desc: 'new3xxxxxxxxxxx'},
{ id:4, name:'4', desc: 'new4xxxxxxxxxxx'},
{ id:5, name:'5', desc: 'new5xxxxxxxxxxx'}
]
curNew
ngOnInit() {
this.route.paramMap.subscribe(param => {
const id = param.get('id')
console.log('参数是', id)
// new 不能使用 改为newone
// +id 是const id 是一个字符,news 中是一个数字, 让其确定一下类型
this.curNew = this.news.find(newone => newone.id === +id)
})
}
}
子路由
- 在
app.module.ts
的父理由里面使用children
来配置子路由 - 在子组件中使用
指定路由出口 - 使用
routerLink=”/home/children”
指定导航链接
目录结构, 目前只有home
组件 和 notfound
组件。
$ ng g c child
app.component.html
<div class='app'>
<h1>使用子路由</h1>
<a routerLink = '/home'>主页</a>
<router-outlet></router-outlet>
</div>
app.module.ts
import .....
............
const appRoutes: Routes = [
{ path:'', redirectTo: '/home', pathMatch: 'full'},
{
path: 'home',
component: HomeComponent,
// 1. 配置子路由
children: [
{
path: 'child',
component: ChildComponent
}
]
},
{ path: '**', component: NotfoundComponent }
]
@NgModule({
...
})
export class AppModule { }
home.component.html
<p>这是首页首页首页~~~~</p>
<!-- 2. 子路由的出口 -->
<router-outlet></router-outlet>
<!-- 3. 指定导航链接 -->
<a routerLink = '/home/child'>子路由</a>
路由激活高亮
init
$ ng g c about
app.component.html
<div class='app'>
<a routerLink = '/home'>主页</a>
<a routerLink = '/about'>关于</a>
<router-outlet></router-outlet>
</div>
app.module.ts
import .....
............
const appRoutes: Routes = [
{ path:'', redirectTo: '/home', pathMatch: 'full'},
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: '**', component: NotfoundComponent }
]
@NgModule({
...
})
export class AppModule { }
长明灯RouterLinkActive
app.component.css
.app {
overflow: hidden;
background-color: skyblue;
}
.actived {
color: #f00;
font-size: 30px;
}
app.component.html
<div class="app">
<h1>路由高亮:</h1>
<a routerLink="/home" routerLinkActive="actived" [routerLinkActiveOptions]="{ exact: true }">首页</a>
<a routerLink="/about" routerLinkActive="actived">关于</a>
<router-outlet></router-outlet>
</div>
完
本文首次发布于 Azr的博客, 作者 @azrrrrr ,转载请保留原文链接.
原文链接: http://amor9.cn/2019/01/28/ng5/