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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 如何在 Angular 路由中使用路由解析器

简介

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

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

可供使用的一个 API 是 Hacker News API。Hacker News 是一个用于分享链接和讨论的网站。该 API 可用于检索最受欢迎的帖子并显示有关单个帖子的信息。

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

先决条件

要完成本教程,您需要:

  • 本地安装了 Node.js,您可以按照《如何安装 Node.js 并创建本地开发环境》中的步骤进行操作。
  • 一些关于设置 Angular 项目的熟悉程度。

本教程已使用 Node v15.3.0、npm v6.14.9、@angular/core v11.0.1、@angular/common v11.0.1、@angular/router v11.0.1 和 rxjs v6.6.0 进行验证。

步骤 1 — 设置项目

为了本教程的目的,您将从使用 @angular/cli 生成的默认 Angular 项目构建。

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

这将配置一个新的 Angular 项目,其中样式设置为 “CSS”(而不是 “Sass”、“Less” 或 “Stylus”),启用了路由,并跳过了测试。

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

cd angular-route-resolvers-example

此时,您已经有了一个带有 @angular/router 的新的 Angular 项目。

步骤 2 — 构建解析器

让我们首先实现一个解析器,在 2 秒延迟后返回一个字符串。这个小的概念验证可以帮助您探索可以应用于更大项目的路由连接的基础知识。

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

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

这将使用 @angular/cli 生成名为 news 的解析器:

import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
@Injectable({
  providedIn: 'root'
})
export class NewsResolver implements Resolve<Observable<string>> {
  resolve(): Observable<string> {
    return of('Route!').pipe(delay(2000));
  }
}

实现 Angular 路由的 Resolve 接口需要该类具有一个 resolve 方法。该方法返回的任何内容都将是已解析的数据。

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

步骤 3 — 配置路由

为了体验两个不同的路由,您将需要两个新组件。home 将是登陆页面。top 将展示来自 Hacker News API 的热门帖子。

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

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

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

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

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

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { NewsResolver } from './news.resolver';
import { TopComponent } from './top/top.component';
import { HomeComponent } from './home/home.component';
const routes: Routes = [
  {
    path: '',
    pathMatch: 'full',
    component: HomeComponent
  },
  {
    path: 'top',
    component: TopComponent,
    resolve: { message: NewsResolver }
  }
];
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

请注意,解析器就像服务一样提供,然后您将解析器与路由定义一起包括在内。这里已解析的数据将在 message 键下可用。

步骤 4 — 在组件中访问已解析的数据

在组件中,您可以使用 ActivatedRoutesnapshot 对象的 data 属性来访问已解析的数据:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({ ... })
export class TopComponent implements OnInit {
  data: any;
  constructor(private route: ActivatedRoute) {}
  ngOnInit(): void {
    this.data = this.route.snapshot.data;
  }
}

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

<p>The message: {{ data.message }}</p>

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

npm start

并在 Web 浏览器中访问 localhost:4200/top

The message: Route!

您会注意到,当导航到 top 路由时,现在会有 2 秒的延迟,因为数据首先被解析了。

步骤 5 — 从 API 解析数据

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

您将需要使用 HttpClient 来请求端点。

首先,将 HttpClientModule 添加到 app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

然后,创建一个新的服务:

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

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

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
  providedIn: 'root'
})
export class NewsService {
  constructor(private http: HttpClient) { }
  getTopPosts() {
    const endpoint = 'https://hacker-news.firebaseio.com/v0/topstories.json';
    return this.http.get(endpoint);
  }
}

现在,您可以使用 NewsService 替换 NewsResolver 中的字符串代码:

import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Observable } from 'rxjs';
import { NewsService } from './news.service';
export class NewsResolver implements Resolve<any> {
  constructor(private newsService: NewsService) {}
  resolve(): Observable<any> {
    return this.newsService.getTopPosts();
  }
}

此时,如果您在浏览器中查看 top 路由,将会看到一个代表 Hacker News 上热门帖子的 id 列表。

步骤 6 — 访问路由参数

您可以使用 ActivatedRouteSnapshot 对象在解析器中访问当前路由参数。

以下是一个示例,您可以在解析器中使用 ActivatedRouteSnapshot 获取当前路由的 id 参数。

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

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

然后,修改 post.resolver.ts 以使用 ActivatedRouteSnapshot

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { NewsService } from './news.service';
@Injectable({
  providedIn: 'root'
})
export class PostResolver implements Resolve<any> {
  constructor(private newsService: NewsService) {}
  resolve(route: ActivatedRouteSnapshot): Observable<any> {
    return this.newsService.getPost(route.paramMap.get('id'));
  }
}

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

// ...
export class NewsService {
  constructor(private http: HttpClient) { }
  // ...
  getPost(postId: string) {
    const endpoint = 'https://hacker-news.firebaseio.com/v0/item';
    return this.http.get(`${endpoint}/${postId}.json`);
  }
}

并且在 app-routing.module.ts 中添加 PostResolverpost/:id 路由:

// ...
import { PostResolver } from './post.resolver';
// ...
const routes: Routes = [
  // ...
  {
    path: 'post/:id',
    component: PostComponent,
    resolve: { newsData: PostResolver }
  }
];
// ...

接下来,创建新的 PostComponent

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

然后,修改 post.component.ts 以使用快照数据:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({ ... })
export class PostComponent implements OnInit {
  data: any;
  constructor(private route: ActivatedRoute) { }
  ngOnInit(): void {
    this.data = this.route.snapshot.data;
  }
}

并修改 post.component.html 以显示 title

<p>{{ data.newsData.title }}</p>

现在,如果用户访问 http://localhost:4200/post/15392112,将会解析帖子 id 为 15392112 的数据。

步骤 7 — 处理错误

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

import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { NewsService } from './news.service';
@Injectable()
export class NewsResolver implements Resolve<any> {
  constructor(private newsService: NewsService) {}
  resolve(): Observable<any> {
    return this.newsService.getTopPosts().pipe(catchError(() => {
      return of('data not available at this time');
    }));
  }
}

或者,您可以返回一个 EMPTY observable 并将用户重定向到根路径:

import { Injectable } from '@angular/core';
import { Router, Resolve } from '@angular/router';
import { Observable, EMPTY } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { NewsService } from './news.service';
@Injectable()
export class NewsResolver implements Resolve<any> {
  constructor(private router: Router, private newsService: NewsService) {}
  resolve(): Observable<any> {
    return this.newsService.getTopPosts().pipe(catchError(() => {
      this.router.navigate(['/']);
      return EMPTY;
    }));
  }
}

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

结论

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

如果您想了解更多关于 Angular 的知识,请查看我们的 Angular 专题页面,了解更多练习和编程项目。


目录
相关文章
|
29天前
|
存储 JavaScript 前端开发
Vue3权限控制全攻略:路由与组件层面的用户角色与权限管理方法深度解析
Vue3权限控制全攻略:路由与组件层面的用户角色与权限管理方法深度解析
103 2
|
1月前
|
移动开发 JavaScript 前端开发
Javaweb之Vue路由的详细解析
Vue.js是一款备受欢迎的前端框架,以其简洁的API和组件化开发模式著称。Vue Router作为其官方路由管理器,在构建单页面应用(SPA)时发挥关键作用,通过URL变化管理组件切换,实现无刷新过渡。本文将详细介绍Vue Router的基础概念、主要功能及使用步骤,帮助JavaWeb开发者快速掌握其工作原理及实践应用。
14 1
|
3月前
|
Java 数据库 API
JSF与JPA的史诗级联盟:如何编织数据持久化的华丽织锦,重塑Web应用的荣耀
【8月更文挑战第31天】JavaServer Faces (JSF) 和 Java Persistence API (JPA) 分别是构建Java Web应用的用户界面组件框架和持久化标准。结合使用JSF与JPA,能够打造强大的数据驱动Web应用。首先,通过定义实体类(如`User`)和配置`persistence.xml`来设置JPA环境。然后,在JSF中利用Managed Bean(如`UserBean`)管理业务逻辑,通过`EntityManager`执行数据持久化操作。
55 0
|
3月前
|
Java Spring
🔥JSF 与 Spring 强强联手:打造高效、灵活的 Web 应用新标杆!💪 你还不知道吗?
【8月更文挑战第31天】JavaServer Faces(JSF)与 Spring 框架是常用的 Java Web 技术。本文介绍如何整合两者,发挥各自优势,构建高效灵活的 Web 应用。首先通过 `web.xml` 和 `ContextLoaderListener` 配置 Spring 上下文,在 `applicationContext.xml` 定义 Bean。接着使用 `@Autowired` 将 Spring 管理的 Bean 注入到 JSF 管理的 Bean 中。
64 0
|
3月前
|
开发者 iOS开发 C#
Uno Platform 入门超详细指南:从零开始教你打造兼容 Web、Windows、iOS 和 Android 的跨平台应用,轻松掌握 XAML 与 C# 开发技巧,快速上手示例代码助你迈出第一步
【8月更文挑战第31天】Uno Platform 是一个基于 Microsoft .NET 的开源框架,支持使用 C# 和 XAML 构建跨平台应用,适用于 Web(WebAssembly)、Windows、Linux、macOS、iOS 和 Android。它允许开发者共享几乎全部的业务逻辑和 UI 代码,同时保持原生性能。选择 Uno Platform 可以统一开发体验,减少代码重复,降低开发成本。安装时需先配置好 Visual Studio 或 Visual Studio for Mac,并通过 NuGet 或官网下载工具包。
276 0
|
3月前
|
容器 iOS开发 Linux
震惊!Uno Platform 响应式 UI 构建秘籍大公开!从布局容器到自适应设计,带你轻松打造跨平台完美界面
【8月更文挑战第31天】Uno Platform 是一款强大的跨平台应用开发框架,支持 Web、桌面(Windows、macOS、Linux)及移动(iOS、Android)等平台,仅需单一代码库。本文分享了四个构建响应式用户界面的最佳实践:利用布局容器(如 Grid)适配不同屏幕尺寸;采用自适应布局调整 UI;使用媒体查询定制样式;遵循响应式设计原则确保 UI 元素自适应调整。通过这些方法,开发者可以为用户提供一致且优秀的多设备体验。
140 0
|
3月前
|
SEO 搜索推荐 数据采集
让 JSF 应用秒变搜索引擎宠儿!揭秘 SEO 优化的神奇魔法,让你的网站脱颖而出!
【8月更文挑战第31天】随着互联网的发展,搜索引擎已成为用户获取信息的主要途径,SEO 对 Web 应用至关重要。本文介绍如何提升 JavaServer Faces(JSF)应用的 SEO 友好性,包括关键词优化、网页结构优化和外部链接建设等基础知识,并提出了使用语义化 HTML 标签、优化页面标题和描述、生成静态 HTML 页面及 URL 重写等具体策略,帮助您的网站在搜索引擎中获得更高排名。
32 0
|
3月前
|
安全 开发者
精通Angular路由管理:从基础设置到高级配置,打造复杂SPA导航系统的全方位指南
【8月更文挑战第31天】在单页应用(SPA)中,路由管理至关重要。Angular通过其强大的路由模块提供灵活高效的解决方案。本文通过代码示例详细介绍如何在Angular中设置和管理路由,包括基础路由配置、懒加载、路由保护及高级配置,帮助开发者构建高效安全的导航系统,满足复杂SPA需求。随着Angular的发展,路由管理将更加完善,值得持续关注。
33 0
|
4月前
|
监控 JavaScript 前端开发
Vue组件与路由精通指南:深入解析组件化开发与路由管理
Vue组件和路由详解:组件是应用的基石,用于封装可重用代码,可扩展HTML元素。动态组件根据需求切换。父子组件间通过props单向数据流通信,子组件使用`$emit`触发父组件方法。Vue Router提供`router.push`、`.replace`、`.go`等方法管理导航,`$route`对象包含`path`、`params`、`query`等信息。路由钩子如`beforeEach`允许在导航发生时执行逻辑。
|
3月前
如何在 Angular 路由中使用路由守卫
如何在 Angular 路由中使用路由守卫
46 0

推荐镜像

更多