- (如果是和我一样的小白,直接学习官文上的路由和导航的;在里程碑3:英雄特征区开始的,其中前几步是让我们把服务的部分代码拿过来;然后更改代码和目录结构,直接看后面总结代码,因为中间省略了很多;按照步骤来是很坑的;大佬请忽略;)
- 进入正题之前,先了解到--已知用户场景是;首页为数据列表,点击其中任意可以跳转到对应数据的详情页,点击详情页的回退可以返回数据列表页面,同时数据列表页面被该数据是为选中的数据,样式有所更改;
- 第一步,配置路由,这里将hero-detail作为需要传递参数的组件模块;(步骤可更换,理解就可以)
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { HeroListComponent } from './hero-list/hero-list.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component'; const heroesRoutes: Routes = [ {path: 'heroes', component: HeroListComponent}, {path: 'hero/:id', component: HeroDetailComponent} // 路由带参; hero为路径 /:id 为占位参数,即这里是将传来动态参数id;如localhost:4200/hero/1;即访问id为1的数据; ]; @NgModule({ imports: [RouterModule.forChild(heroesRoutes)], exports: [RouterModule] }) export class HeroesRoutingModule { }
- 第二步,显示hero-list的列表数据
-
<h2>Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes$ | async" [class.selected]="hero.id === selectedId"> <!-- 视图带参跳转 --> <a [routerLink]="['/hero', hero.id]"> <span class="badge">{{hero.id}}</span> {{hero.name}} </a> <!-- <a routerLink="/hero/{{hero.id}}"> <span class="badge">{{hero.id}}</span> {{hero.name}} </a> --> </li> </ul> <button routerLink="/sidekicks">Go to sidekicks</button>
import { Observable } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Hero } from '../hero'; import { HeroService } from '../hero.service'; @Component({ selector: 'app-hero-list', templateUrl: './hero-list.component.html', styleUrls: ['./hero-list.component.css'] }) export class HeroListComponent implements OnInit { heroes$: Observable<Hero[]>; selectedId: number; heroes: Hero[]; constructor( private heroService: HeroService, private activatedRoute: ActivatedRoute, private router: Router ) { } ngOnInit() { this.getHeroList(); // this.heroes$ = this.heroService.getHeroes(); } getHeroList(){ // activatedRoute.paramMap 属性是一个路由参数的可观察对象; 当导航到这个组件时,paramMap会将获取对应id;并订阅相关值;设置到selectedId; this.heroes$ = this.activatedRoute.paramMap.pipe( switchMap(params => { this.selectedId = +params.get('id'); // + 将字符串转化成数字类型 ;接收从详情页传递来的id 值进行回退选中的显示 return this.heroService.getHeroes(); // 获取列表数据 }) ); // 通过subscribe()订阅返回 // this.heroService.getHeroes().subscribe(item => this.heroes = item); // console.log(this.heroes); } // 跳转方法 goDetailById(heroId){ this.router.navigate(['hero', heroId]); // 路由跳转; // this.router.navigate(['hero',{ id: heroId, flag: true}]); // 多个参数 } }
- 第三步,处理传递到hero-detail的路由参数
-
<h2>HEROES</h2> <div *ngIf="hero$ | async as hero"> <h3>"{{ hero.name }}"</h3> <div> <label>Id: </label>{{ hero.id }}</div> <div> <label>Name: </label> <input [(ngModel)]="hero.name" placeholder="name"/> </div> <p> <button (click)="gotoHeroes(hero)">Back</button> </p> </div>
import { switchMap } from 'rxjs/operators'; import { Component, OnInit, Input } from '@angular/core'; import { Router, ActivatedRoute, ParamMap } from '@angular/router'; // 导入类 import { Observable } from 'rxjs'; import { Hero } from '../hero'; import { HeroService } from '../hero.service'; @Component({ selector: 'app-hero-detail', templateUrl: './hero-detail.component.html', styleUrls: ['./hero-detail.component.css'] }) export class HeroDetailComponent implements OnInit { hero$: Observable<Hero>; //声明 // 服务注入 constructor( private router: Router, private activatedRoute: ActivatedRoute, private heroService: HeroService ) { } ngOnInit() { // ActivatedRoute服务来处理路由的路径和参数;这里接收路由参数ID,获取关联数据 // paramMap; 一个Observable, 包含当前路由的必要参数和可选参数组成的map对象;当这个map值变化,可以使用get(name)获取id参数;然后HeroService获取相关id对应的数据并返回; // switchMap(); 可以取消以前未完成的请求,即发起新ID获取请求时,而service还在接收之前id对应的数据时,switchMap 可以放弃老请求而返回新id 的请求数据; this.hero$ = this.activatedRoute.paramMap.pipe( switchMap((params: ParamMap) => this.heroService.getHero(params.get('id'))) ); } gotoHeroes(hero: Hero) { let heroId = hero ? hero.id : null; this.router.navigate(['heroes', { id: heroId, foo: 'foo' }]); // 路由跳转; } }
- hero.service.ts中需要更改
-
import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { Hero } from './hero'; import { HEROES } from './mock-heroes'; @Injectable({ providedIn: 'root', }) export class HeroService { constructor() { } getHeroes(): Observable<Hero[]> { // 获取列表数据 // TODO: send the message _after_ fetching the heroes return of(HEROES); } getHero(id: number | string) { // 获取指定id数据 return this.getHeroes().pipe( map((heroes: Hero[]) => heroes.find(hero => hero.id === +id)) ); } }
- 最后,官文坑点;
- 虽然下面有解释到部分更改和步骤,但是一步一步操作和最后给出的代码是有些偏差的;导致我这种小白边做边敲代码,发现结果对不上;后来是对着代码往回推,才了解到的;虽然官方文档上有最后的代码,但是我还是重新码了出来,以提高熟练度;