如何在 Angular 路由器中使用路由解析器

简介

处理从API检索和显示数据的一种方法是将用户路由到一个组件,然后在该组件的ngOnInit钩子中调用服务中的方法以获取必要的数据。在获取数据时,组件可能会显示加载指示器。

还有另一种方法可以使用所谓的路由解析器,它允许您在导航到新路由之前获取数据。

一个可用的API是Hacker News API.黑客新闻是一个分享链接和讨论它们的网站。该API可用于检索最受欢迎的帖子,并显示有关单个帖子的信息。

在本教程中,您将实现一个路由解析器,该解析器在导航到显示收集的数据的路线之前从Hacker News API获取数据。

前提条件

要完成本教程,您需要:

本教程通过了Node v15.3.0、npmv6.14.9、@angular/corev11.0.1、@angular/Commonv11.0.1、@angular/routerv11.0.1、rxjsv6.6.0验证。

第一步-设置项目

在本教程中,你将从一个默认的Angular项目中构建,该项目是用@angular/python生成的。

1npx @angular/cli new angular-route-resolvers-example --style=css --routing --skip-tests

这将配置一个新的角度项目,将样式设置为),启用布线,并跳过测试。

导航到新创建的项目目录:

1cd angular-route-resolvers-example

至此,您就有了一个新的角度项目,其名称为@angular/router

第二步-构建解析器

让我们首先实现一个解析器,它在延迟2秒后返回一个字符串。这一小的概念验证有助于探索可应用于较大项目的布线的基本原理。

首先,在解析器自己的文件中为其创建一个单独的类:

1./node_modules/@angular/cli/bin/ng generate resolver news

这将使用@angular/cli来生成一个名为News的解析器:

 1[label src/app/news.resolver.ts]
 2import { Injectable } from '@angular/core';
 3import { Resolve } from '@angular/router';
 4
 5import { Observable, of } from 'rxjs';
 6import { delay } from 'rxjs/operators';
 7
 8@Injectable({
 9  providedIn: 'root'
10})
11export class NewsResolver implements Resolve<Observable<string>> {
12  resolve(): Observable<string> {
13    return of('Route!').pipe(delay(2000));
14  }
15}

实现角度路由器的Resolve接口需要该类有一个Resolve方法。无论从该方法返回什么,都将是已解析的数据。

此代码将在延迟2秒后返回一个换行字符串的可观察对象。

第三步-配置路由

为了体验两条不同的路线,您需要两个新组件。主页将成为网站的登陆页面。而top将以黑客新闻API的热门帖子为特色。

首先,使用@angular/cli生成一个home组件:

1./node_modules/@angular/cli/bin/ng generate component home

然后,使用@angular/cli生成一个top组件:

1./node_modules/@angular/cli/bin/ng generate component top

现在,您可以设置路由模块以包括解析器。

 1[label src/app/app-routing.module.ts]
 2import { NgModule } from '@angular/core';
 3import { Routes, RouterModule } from '@angular/router';
 4
 5import { NewsResolver } from './news.resolver';
 6
 7import { TopComponent } from './top/top.component';
 8import { HomeComponent } from './home/home.component';
 9
10const routes: Routes = [
11  {
12    path: '',
13    pathMatch: 'full',
14    component: HomeComponent
15  },
16  {
17    path: 'top',
18    component: TopComponent,
19    resolve: { message: NewsResolver }
20  }
21];
22
23@NgModule({
24  imports: [RouterModule.forRoot(routes)],
25  exports: [RouterModule]
26})
27export class AppRoutingModule { }

请注意解析器是如何像服务一样提供的,然后您将解析器包含在路由定义中。在这里,已解析的数据将在message键下可用。

第四步-访问组件中的解析数据

在组件中,可以通过ActivatedRoute‘S快照对象的data属性访问解析后的数据:

 1[label src/app/top/top.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3
 4import { ActivatedRoute } from '@angular/router';
 5
 6@Component({ ... })
 7export class TopComponent implements OnInit {
 8  data: any;
 9
10  constructor(private route: ActivatedRoute) {}
11
12  ngOnInit(): void {
13    this.data = this.route.snapshot.data;
14  }
15}

现在,在组件中,您可以访问`Route!像这样的消息:

1[label src/app/top/top.module.html]
2<p>The message: {{ data.message }}</p>

此时,您可以编译您的应用程序:

1npm start

并在Web浏览器中访问本地主机:4200/top

1[secondary_label Output]
2The message: Route!

在导航到top路径时,您会发现现在延迟了2秒,因为数据是先解析的。

第五步-接口数据解析

让我们通过实际从API获取一些数据来使事情变得更加真实。在这里,您将创建一个从Hacker News API获取数据的服务。

您需要HttpClient来请求端点。

首先,将HttpClientModule添加到app.mode.ts中:

 1[label src/app/app.module.ts]
 2
 3import { BrowserModule } from '@angular/platform-browser';
 4import { NgModule } from '@angular/core';
 5import { HttpClientModule } from '@angular/common/http';
 6
 7import { AppRoutingModule } from './app-routing.module';
 8import { AppComponent } from './app.component';
 9
10@NgModule({
11  declarations: [
12    AppComponent
13  ],
14  imports: [
15    BrowserModule,
16    HttpClientModule,
17    AppRoutingModule
18  ],
19  providers: [],
20  bootstrap: [AppComponent]
21})
22export class AppModule { }

然后,创建一个新服务:

1./node_modules/@angular/cli/bin/ng generate service news

这将使用@angular/cli来生成一个名为News的服务:

 1[label src/app/news.service.ts]
 2import { Injectable } from '@angular/core';
 3import { HttpClient } from '@angular/common/http';
 4
 5@Injectable({
 6  providedIn: 'root'
 7})
 8export class NewsService {
 9  constructor(private http: HttpClient) { }
10
11  getTopPosts() {
12    const endpoint = 'https://hacker-news.firebaseio.com/v0/topstories.json';
13
14    return this.http.get(endpoint);
15  }
16}

现在您可以将NewsResolver中的字符串code替换为NewsService

 1[label src/app/news.resolver.ts]
 2import { Injectable } from '@angular/core';
 3import { Resolve } from '@angular/router';
 4import { Observable } from 'rxjs';
 5
 6import { NewsService } from './news.service';
 7
 8export class NewsResolver implements Resolve<any> {
 9  constructor(private newsService: NewsService) {}
10
11  resolve(): Observable<any> {
12    return this.newsService.getTopPosts();
13  }
14}

在这一点上,如果你在浏览器中查看排名靠前的路线,你会看到一个代表黑客新闻热门帖子ID的数字列表。

Step 6-访问路由参数

您可以通过ActivatedRouteSnapshot对象访问您的解析器中当前的路由参数。

下面是一个使用解析器访问当前路由的`id‘参数的示例。

首先,使用@angular/cli生成一个名为post的解析器:

1./node_modules/@angular/cli/bin/ng generate resolver news

然后修改post.Resolver.ts,使用ActivatedRouteSnaphot

 1[label src/app/post.resolver.ts]
 2import { Injectable } from '@angular/core';
 3import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
 4import { Observable } from 'rxjs';
 5
 6import { NewsService } from './news.service';
 7
 8@Injectable({
 9  providedIn: 'root'
10})
11export class PostResolver implements Resolve<any> {
12  constructor(private newsService: NewsService) {}
13
14  resolve(route: ActivatedRouteSnapshot): Observable<any> {
15    return this.newsService.getPost(route.paramMap.get('id'));
16  }
17}

接下来,在NewsService中添加一个getPost方法:

 1[label src/app/news.service.ts]
 2// ...
 3
 4export class NewsService {
 5  constructor(private http: HttpClient) { }
 6
 7  // ...
 8
 9  getPost(postId: string) {
10    const endpoint = 'https://hacker-news.firebaseio.com/v0/item';
11
12    return this.http.get(`${endpoint}/${postId}.json`);
13  }
14}

并将PostResolverpost/:id路由添加到app-routing.mode.ts

 1[label src/app/app-routing.module.ts]
 2// ...
 3
 4import { PostResolver } from './post.resolver';
 5
 6// ...
 7
 8const routes: Routes = [
 9  // ...
10  {
11    path: 'post/:id',
12    component: PostComponent,
13    resolve: { newsData: PostResolver }
14  }
15];
16
17// ...

接下来,创建新的PostComponent

1./node_modules/@angular/cli/bin/ng generate component post

然后将post.Component.ts修改为使用快照数据:

 1[label src/app/post/post.component.ts]
 2import { Component, OnInit } from '@angular/core';
 3import { ActivatedRoute } from '@angular/router';
 4
 5@Component({ ... })
 6export class PostComponent implements OnInit {
 7  data: any;
 8
 9  constructor(private route: ActivatedRoute) { }
10
11  ngOnInit(): void {
12    this.data = this.route.snapshot.data;
13  }
14}

修改post.Component.html,显示标题

1[label src/app/post/post.component.html]
2<p>{{ data.newsData.title }}</p>

现在,如果用户进入http://localhost:4200/post/15392112,,则帖子ID为15392112的数据将被解析。

Step 7-处理错误

如果在获取数据时出现错误,您可以使用RxJS的catch操作符]在解析器中捕获并处理错误。例如,类似于以下内容:

 1[label src/app/news.resolver.ts]
 2import { Injectable } from '@angular/core';
 3import { Resolve } from '@angular/router';
 4
 5import { Observable, of } from 'rxjs';
 6import { catchError } from 'rxjs/operators';
 7
 8import { NewsService } from './news.service';
 9
10@Injectable()
11export class NewsResolver implements Resolve<any> {
12  constructor(private newsService: NewsService) {}
13
14  resolve(): Observable<any> {
15    return this.newsService.getTopPosts().pipe(catchError(() => {
16      return of('data not available at this time');
17    }));
18  }
19}

或者,您可以返回一个EMPTY可观测对象,并将用户返回到根路径:

 1[label src/app/news.resolver.ts]
 2import { Injectable } from '@angular/core';
 3import { Router, Resolve } from '@angular/router';
 4
 5import { Observable, EMPTY } from 'rxjs';
 6import { catchError } from 'rxjs/operators';
 7
 8import { NewsService } from './news.service';
 9
10@Injectable()
11export class NewsResolver implements Resolve<any> {
12  constructor(private router: Router, private newsService: NewsService) {}
13
14  resolve(): Observable<any> {
15    return this.newsService.getTopPosts().pipe(catchError(() => {
16      this.router.navigate(['/']);
17      return EMPTY;
18    }));
19  }
20}

如果从API检索数据时出现错误,这两种方法将带来更好的用户体验。

总结

在本教程中,您实现了一个路由解析器,该解析器在导航到显示所收集数据的路线之前从Hacker News API获取数据。这是通过使用@angular/router@angular/Common/httprxjs来实现的。

如果您想了解更多有关ANGLE的信息,请查看我们的ANGLE主题页面以获取练习和编程项目。

Published At
Categories with 技术
Tagged with
comments powered by Disqus