Richard's Blog

理解Angular中的Resolver

字数统计: 1.1k阅读时长: 4 min
2019/04/27 Share

今天在修改以前同事留下的项目代码时,发现可能以前同事手快通过vscode的autocomplete导入了一些angular内置的类,但是从来没使用过的。平时就觉得Angular的技术栈太深了,官方示例和帮助文档只展示了很少的一部分功能,有些Angular的机制很难被发现。今天就在代码中发现了不小心被导入的resolveDefinition方法,稍微搜索了一下发现了Angular有一个叫Resolver的机制,这个机制在Angular4.x中就已经存在。下面是找到的一篇文章,翻译一下放在这里。

原文链接Understanding Resolvers in Angular.

英语水平有限,内容未必准确

像所有Angular中重要的东西一样,resolver也是一个类。事实上,Resolver是一个service,必须被放到根module的providers

为了理解如果使用resolvers,我们来看看当一个人点击了一个链接后,流程上发生了什么。

通常的路由流程

  1. 用户点击了链接。
  2. Angular加载各自的组件(components)。

带Resolver的路由流程

  1. 用户点击了链接。
  2. Angular执行某些代码后返回一个value或者observable。
  3. 你可以在要加载的component类的构造器(constructor)或者ngOnInit方法中获取回返的value或者observable。
  4. 使用你获取到的数据做你想做的。
  5. 然后加载你的component。

第2,3,4步就是通过在Resolver中的代码完成的。

所以简单的总结一下,resolver的作用是在链接被点击之后,component被加载之前可以执行一段代码。

让我们看看如何创建它,在哪里使用它和怎么使用它?

创建一个Resolver

  1. 创建一个service。
  2. 从‘@angular/router’导入”Resolve”接口。
  3. 在你的类中实现接口。
  4. 重写resolve()方法。
  5. Resolve方法有两个参数,一个是routesnapshot,另一个是statesnapshot点击这个链接获取更多信息。
  6. 如果你想在后面加载的component类中使用Resolve中获得的数据,那么resolve方法应该返回一个值或者observable。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AppResolver implements Resolve<any> {

constructor(
private http: Http
) { }

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
console.log('Logging collected route Prameter', route.params['name']);
return this.http.get('https://jsonplaceholder.typicode.com/posts');
}
}

在上面的代码中,我获取了路由的参数然后在console中打印了出来。你可以在resolve中使用路由参数来决定如何加载你的component甚至重定向到其他的页面。你可以在resolver中做很多事情。

最终我们返回了一个observable。

在路由中定义一个Resolver

路由是定义在数组中的对象。每个对象都有一些key像path, component, redirectTo, pathMatch, resolve等等。叫resolve的key需要接收一个对象,你需要定义此对象的key值然后把你的resolver service当作value值。做这些之前你需要导入你的resolver service并提供给NgModule注解中的providers集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { Routes, RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { ResOneComponent } from './res-one/res-one.component';
import { ResTwoComponent } from './res-one/res-two.component';
import { ResHomeComponent } from './res-one/res-home.component';
import { AppResolver } from './app-resolver.service';

const routes: Routes = [
{
path: '',
component: ResHomeComponent
},
{
path: 'one/:name',
component: ResOneComponent,
resolve: {
cres: AppResolver
}
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [AppResolver]
})
export class AppRouterModule {

}

cres是我自己定义的AppResolver service的key值

使用Resolver

我将在我的component中使用这个resolver,这个component是在执行了resolver之后加载的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { OnInit, Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import 'rxjs/add/operator/map';

@Component({
selector: 'app-res-one',
templateUrl: './res-one.component.html',
styleUrls: ['./res-one.component.css'],
})
export class ResOneComponent implements OnInit {

constructor(
private actr: ActivatedRoute
) {
this.actr.data.map(data => data.cres.json()).subscribe(res => {
console.log(res);
});
}

ngOnInit(): void {
console.log('Component Initiated');
}

}

我在activated router中映射了我的数据,使用我在路由对象中定义的cres获取到了我的resolver。

以下是我的输出

output

我导航至叫’one’的路由,并带上了’ophir’参数。然后我在resolver中获取了这个参数并打印在console上。然后我发出了一个请求然后返回了一个observable。我在我的类中订阅了这个observable,我的component将在请求完成后被初始化。

这就是我怎样控制这个流程,在路由被初始化后开始,然后继续在resolver中发起http请求,然后在component中获得数据。最后我的component的DOM开始初始化。

CATALOG
  1. 1. 通常的路由流程
  2. 2. 带Resolver的路由流程
  3. 3. 创建一个Resolver
  4. 4. 在路由中定义一个Resolver
  5. 5. 使用Resolver