五。Angular — 路由

路由是 Angular 应用程序的核心,它加载与所请求路由相关联的组件,以及获取特定路由的相关数据。

Posted by Azr on January 28, 2019

在用户使用应用程序时,Angular的路由器能让用户从一个视图导航到另一个视图。

概览

例子

浏览器具有我们熟悉的导航模式:

  • 在地址栏输入URL,浏览器就会导航到相应的页面。
  • 在页面中点击链接,浏览器就会导航到一个新页面。
  • 点击浏览器的前进和后退按钮,浏览器就会在你的浏览历史中向前或向后导航。

Angular的Router借鉴了这个模型。把浏览器中的URL看做一个操作指南, 据此导航到一个由客户端生成的视图,并可以把参数传给支撑视图的相应组件,帮它决定具体该展现哪些内容。

开发人员为页面中的链接绑定一个路由,这样,当用户点击链接时,就会导航到应用中相应的视图。 当用户点击按钮、从下拉框中选取,或响应来自任何地方的事件时,开发人员也可以在代码控制下进行导航。 路由器还在浏览器的历史日志中记录下这些活动,这样浏览器的前进和后退按钮也能照常工作。

说明

  1. 路由是实现 SPA(单页应用程序) 的基础设施。
  2. 作用:让用户从一个视图导航到另一个视图。
  3. 路由是:URL 和 组件的对应规则。
  4. 使用:HTML5风格(history.pushState)的导航。
  5. 支持:重定向(可以默认调整活动页面)、路由高亮(会让当前点击的路由有高亮的效果)、通配符路由(配置一些有用的路由)、路由参数(通过路由参数来区分不同的新闻详情页)、子路由、路由模块(当路由比较复杂,分为一个模块)、路由守卫、异步路由等。

使用

  1. 在index.html中设置

  2. 导入 RouterModule 模块。

  3. 配置路由规则 appRoutes

  4. RouterModule.forRoot(appRoutes) 模块配置在根模块中。

  5. 使用 指定路由出口。

  6. 使用 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 { }
       
    
    1. 导入路由模块
    2. 配置路由规则
    3. 配置路由模块,做为跟模块的依赖项

    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的说明

  1. 问题说明:服务应该是单例的,某些场景下会造成服务多次注册,破坏服务的单例特性。
  2. 比如:路由懒加载的情况。
  3. 解决方式:使用模块的 forRoot() 方法导入模块。
  4. 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

不可以匹配的路径是

  1. /new 2
  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)
    })
  }
}

子路由

  1. app.module.ts的父理由里面使用children来配置子路由
  2. 在子组件中使用 指定路由出口
  3. 使用 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/