0
点赞
收藏
分享

微信扫一扫

从 Angular Route 中提前获取数据

介绍

提前获取意味着在数据呈现在屏幕之前获取到数据。本文中,你将学到,在路由更改前怎么获取到数据。通过本文,你将学会使用 ​​resolver​​​, 在 ​​Angular App​​​ 中应用 ​​resolver​​,应用到一个公共的预加载导航。

你为什么应该使用 ​​Resolver​

​Resolver​​​ 在路由跟组件之间扮演着中间件服务的角色。假设你有一个表单,没有数据时,你想向用户一个空的表单,当在加载用户数据时展示一个 ​​loader​​​,然后当数据返回时,填充表单并隐藏 ​​loader​​。

通常,我们都会在组件的 ​​ngOnInit()​​ 钩子函数中获取数据。也就是说,组件加载完之后,我们发起数据请求。

在 ​​ngOnInit()​​​ 中操作,我们需要在每个需要的组件加载后,在其路由页面中添加 ​​loader​​​ 展示。​​Resolver​​​ 可以简化 ​​loader​​​ 的添加使用。你可以只添加一个适用于每个路由的 ​​loader​​​,而不是每个路由中都添加 ​​loader​​。

本文将结合示例来解析 ​​resolver​​ 的知识点。以便于你可以牢记它并在项目中使用它。

在应用中使用 ​​Resolver​

为了在应用中使用 ​​resolver​​​,你需要准备一些接口。你可以通过 JSONPlaceholder 来模拟,而不需要自己开发。

​JSONPlaceholder​​ 是一个很棒的接口资源,你可以借助它更好学习前端的相关概念而不被接口所约束。

现在,接口的问题解决了,我们可以开始 ​​resolver​​​ 的应用了。一个 ​​resolver​​ 就是一个中间件服务,所以我们将创建一个服务。

$ ng g s resolvers/demo-resolver --skipTests=true

--skipTests=true 跳过生成测试文件

​src/app/resolvers​​​ 文件夹中创建了一个服务。​​resolver​​​ 接口中有一个 ​​resolve()​​​ 方法,它有两个参数:​​route​​​(​​ActivatedRouteSnapshot​​​ 的实例)和 ​​state​​​(​​RouterStateSnapshot​​ 的实例)。

​loader​​​ 通常是在 ​​ngOnInit()​​​ 中编写所有的 ​​AJAX​​​ 请求,但是逻辑将会在 ​​resolver​​​ 中实现,替代 ​​ngOnInit()​​。

接着,创建一个服务来获取 ​​JSONPlaceholder​​​ 中列表数据。然后在 ​​resolver​​​ 中底调用,接着在路由中配置 ​​resolve​​​信息,(页面将会等待)直到 ​​resolver​​​ 被处理。在 ​​resolver​​ 被处理之后,我们可以通过路由来获取数据然后展示在组件中。

创建服务并编写逻辑获取列表数据

$ ng g s services/posts --skipTests=true

现在,我们成功创建了服务,是时候编写一个 ​​AJAX​​ 请求的逻辑了。

​model​​ 的使用能够帮助我们减少错误。

$ ng g class models/post --skipTests=true

post.ts

export class Post {
id: number;
title: string;
body: string;
userId: string;
}

​model​​​ 就绪,是时候获取帖子 ​​post​​ 的数据了。

post.service.ts

import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Post } from "../models/post";

@Injectable({
providedIn: "root"
})
export class PostsService {
constructor(private) {}

getPostList() {
let URL = "https://jsonplaceholder.typicode.com/posts";
return this._http.get<Post[]>(URL);
}
}

现在,这个服务随时可被调用。

demo-resolver.service.ts

import { Injectable } from "@angular/core";
import {
Resolve,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from "@angular/router";
import { PostsService } from "../services/posts.service";

@Injectable({
providedIn: "root"
})
export class DemoResolverService implements Resolve<any> {
constructor(private) {}

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this._postsService.getPostList();
}
}

帖子列表数据从 ​​resolver​​​ 中返回。现在,你需要一个路由去配置 ​​resolver​​,从路由获取数据,然后让数据展示在组件中。为了进行路由跳转,我们需要创建一个组件。

$ ng g c components/post-list --skipTests=true

为了路由可见,在 ​​app.component.ts​​​ 添加 ​​router-outlet​​。

<router-outlet></router-outlet>

现在,你可以配置 ​​app-routing.module.ts​​​ 文件了。下面的片段代码将有助于你理解路由配置 ​​resolver​​。

app-routing-module.ts

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { PostListComponent } from "./components/post-list/post-list.component";
import { DemoResolverService } from "./resolvers/demo-resolver.service";

const routes: Routes = [
{
path: "posts",
component: PostListComponent,
resolve: {
posts: DemoResolverService
}
},
{
path: "",
redirectTo: "posts",
pathMatch: "full"
}
];

@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule

一个 ​​resolve​​​ 已经添加到路由配置中了,它将发起一个 ​​HTTP​​​ 请求,然后当 ​​HTTP​​​ 请求成功返回后,允许组件初始化。路由将组装获取到的 ​​HTTP​​ 请求返回的数据。

怎么应用一个预加载导航

向用户展示一个请求正在进行,我们在 ​​AppComponent​​​ 中编写一个公共且简单的 ​​loader​​。你可以根据需要自定义。

app.component.html

<div class="loader" *ngIf="isLoader">
<div>Loading...</div>
</div>
<router-outlet></router-outlet>

app.component.ts

import { Component } from "@angular/core";
import {
Router,
RouterEvent,
NavigationStart,
NavigationEnd
} from "@angular/router";

@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"]
})
export class AppComponent {
isLoader: boolean;

constructor(private) {}

ngOnInit() {
this.routerEvents();
}

routerEvents() {
this._router.events.subscribe((event: RouterEvent) => {
switch (true) {
case event instanceof NavigationStart: {
this.isLoader = true;
break;
}
case event instanceof NavigationEnd: {
this.isLoader = false;
break;
}
}
});
}
}

当导航开始,​​isLoader​​​ 值被赋予 ​​true​​,页面中,你将看到下面的效果。

从 Angular Route 中提前获取数据_前端

当 ​​resolver​​ 处理完之后,它将会被隐藏。

现在,是时候从路由中获取值并将其展示出来。

port-list.component.ts

import { Component, OnInit } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router";
import { Post } from "src/app/models/post";

@Component({
selector: "app-post-list",
templateUrl: "./post-list.component.html",
styleUrls: ["./post-list.component.scss"]
})
export class PostListComponent implements OnInit {
posts: Post[];

constructor(private) {
this.posts = [];
}

ngOnInit() {
this.posts = this._route.snapshot.data["posts"];
}
}

如上所示,​​post​​​ 的值来自 ​​ActivatedRoute​​​ 的快照信息 ​​data​​。这值都可以获取,只要你在路由中配置了相同的信息。

我们在 ​​HTML​​ 进行如下渲染。

<div class="post-list grid-container">
<div class="card" *ngFor="let post of posts">
<div class="title"><b>{{post?.title}}</b></div>
<div class="body">{{post.body}}</div>
</div>
</div>

​CSS​​ 片段样式让其看起来更美观。

port-list.component.css

.grid-container {
2 display: grid;
3 grid-template-columns: calc(100% / 3) calc(100% / 3) calc(100% / 3);
4}
5.card {
6 margin: 10px;
7 box-shadow: black 0 0 2px 0px;
8 padding: 10px;
9}

推荐使用 scss 预处理器编写样式

从路由中获取数据之后,它会被展示在 ​​HTML​​ 中。效果如下快照。

从 Angular Route 中提前获取数据_Angular.js_02

至此,你已经了解完怎么应用 ​​resolver​​ 在你的项目中了。

总结

结合用户体验设计,在 ​​resolver​​​ 的加持下,你可以提升你应用的表现。了解更多,你可以戳官网。

本文是译文,采用的是意译的方式,其中加上个人的理解和注释,原文地址是:www.pluralsight.com/guides/pref…


举报

相关推荐

0 条评论