Angular Router: 理解Router State
原文地址点 这里 在本文中,我们将深入了解RouterState。
RouterState and RouterStateSnapshot在导航过程中,应用重定向后,路由器会创建一个RouterStateSnapshot。 什么是RouterStateSnapshot,它与RouterState有什么不同? RouteStateSnapshot是一个不可变数据结构,表示路由器在特定时刻的状态。 任何时候添加或删除组件或更新参数,都会创建一个新的快照。 RouterState类似于RouteStateSnapshot,但它表示路由器随时间变化的状态。 RouterStateSnapshotinterface RouterStateSnapshot { root: ActivatedRouteSnapshot; }
interface ActivatedRouteSnapshot { url: UrlSegment[]; params: {[name:string]:string};
data: {[name:string]:any};
queryParams: {[name:string]:string};
fragment: string;
root: ActivatedRouteSnapshot;
parent: ActivatedRouteSnapshot;
firstchild: ActivatedRouteSnapshot;
children: ActivatedRouteSnapshot[];
}
可以看到,RouterStateSnapshot是一个树结构,表示当前激活路由的快照。当前节点下的所有子节点都包含了当前URL片段,获取的参数以及解析出的数据。 [
{
path: ':folder',children: [
{
path: '',component: ConversationsCmp
},{
path: ':id',component: ConversationCmp,children: [
{
path: 'messages',component: MessagesCmp
},{
path: 'messages/:id',component: MessageCmp,resolve: {
message: MessageResolver
}
}
]
}
]
}
]
当我们导航到“/inbox/33/messages/44”时,路由器将查看URL,并构造以下RouterStateSnapshot: 之后路由器将ConversationCmp实例化并将MessageCmp放到里面 为避免不必要的DOM修改,当相应路由的参数发生变化时,路由器将再次使用组件。 在此示例中,消息组件的id参数已从44更改为45.这意味着我们不能将ActivatedRouteSnapshot注入到MessageCmp中,因为该快照将始终将id参数设置为44,里面的数据已经旧了。 路由器状态快照表示应用程序在某一时刻的状态,因此命名为“快照”。 但组件能保持激活状态很长时间,其显示的数据可能会改变。 所以只有快照能保存它 - 我们需要一个数据结构,使我们能够处理变化。 介绍RouterState!interface RouterState {
snapshot: RouterStateSnapshot; //returns current snapshot
root: ActivatedRoute;
}
interface ActivatedRoute {
snapshot: ActivatedRouteSnapshot; //returns current snapshot
url: Observable<UrlSegment[]>;
params: Observable<{[name:string]:string}>;
data: Observable<{[name:string]:any}>;
queryParams: Observable<{[name:string]:string}>;
fragment: Observable<string>;
root: ActivatedRout;
parent: ActivatedRout;
firstchild: ActivatedRout;
children: ActivatedRout[];
}
RouterState和ActivatedRoute类似于它们的快照,区别在于它们是可观察流(observables),这对于处理随时间变化的值非常有用。 路由器实例化的任何组件都可以注入其ActivatedRoute。 @Component({
template: ` Title: {{(message|async).title}} ... `
})
class MessageCmp {
message: Observable<Message>;
constructor(r: ActivatedRoute) {
this.message = r.data.map(d => d.message);
}
}
如果我们从“/inbox/33/messages/44”导航到“/inbox/33/messages/45”,则可观察数据流将使用新的消息对象发出一组新的数据,组件将显示Message 45。 访问快照流在大多数时候都是很方便的,但有时候我们想要一个可以马上检查的状态快照。 @Component({...})
class MessageCmp {
constructor(r: ActivatedRoute) {
r.url.subscribe(() => {
r.snapshot; // 任何时间 url变化 则调用此回调
});
}
}
ActivatedRouteActivatedRoute提供对url,params,data,queryParams和fragment流的访问。我们将仔细讨论这些,但首先让我们来看看它们之间的关系。 在一个路由中,URL的变化是一切变化的源头。这是必然的,因为用户可以直接修改它。 每当URL变化时,路由器从中导出一组新的参数:路由器将匹配的URL段的位置参数(例如“:id”)和最后匹配的URL段的矩阵参数进行组合。 这个操作是高纯度的—-URL必须改变才能改变参数。或者换句话说,相同的URL将始终导致相同的参数集合。 接下来,路由器调用路由的数据解析器( route’s data resolvers),并将结果与提供的静态数据组合。 由于数据解析器是任意函数,因此当给定相同的URL时,路由器不能保证您将获得相同的对象。 更重要的是,通常情况不一定如此! URL包含资源的ID,它是固定的,数据解析器提取该资源的内容,这些内容通常会随时间而变化。 最后,被激活的路由提供queryParams和fragment observables流。 与其他特定的某个路由上的可观察对象相反,查询参数和片段可以在多个路由之间共享。 URL如下: @Component({...})
class ConversationCmp {
constructor(r: ActivatedRoute) {
r.url.subscribe((s:UrlSegment[]) => {
console.log("url",s);
});
}
}
从“/inbox/33/messages/44” 到 “/inbox/33/messages/45”,我们将看到: url [{path: ‘messages’,params: {}},{path: ‘44’,params: {}}]
url [{path: ‘messages’,{path: ‘45’,params: {}}]
我们不会经常监听URL变化,因为这些是很底层的。 一个可以实用的用例是当一个组件被通配符路由激活时。 因为在这种情况下,URL段的数组不是固定的,检查它可能会向用户显示不同的数据,这个功能可能是有用的。 Params如下: @Component({...})
class MessageCmp {
constructor(r: ActivatedRoute) {
r.params.subscribe((p => {
console.log("params",params);
});
}
}
从“/inbox/33/messages;a=1/44;b=1”到“/inbox/33/messages;a=2/45;b=2” params {id: ‘44’,b: ‘1’}
params {id: ‘45’,b: ‘2’}
首先注意的是:id参数是一个字符串(当处理URL时,我们总是使用字符串)。其次,路由只能获得最后一个URL段的矩阵参数。 这就是为什么’a’参数不存在的原因。 Data我们调整以上配置,看看data observable的工作原理。 { path: 'messages/:id',data: { allowReplyAll: true },resolve: { message: MessageResolver }
}
MessageResolver定义如下: class MessageResolver implements Resolve<any> {
constructor(private repo: ConversationsRepo,private currentUser: User) {}
resolve(route: ActivatedRouteSnapshot,state: RouteStateSnapshot):
Promise<Message> {
return this.repo.fetchMessage(route.params['id'],this.currentUser);
}
}
data属性用于传递一个编辑好的对象到激活的路由上,它在应用程序的整个生命周期内都不会改变。 resolve属性用于动态数据。 请注意,在上面的配置中,“message:MessageResolver”行不会告诉路由器实例化解析器。 它指示路由器通过依赖注入获取一个实例。 这意味着您必须在某个地方的提供商列表中注册“MessageResolver”。 function resolver(route: ActivatedRouteSnapshot,state: RouteStateSnapshot): Promise<Message> {
return repo.fetchMessage(route.params['id'],this.currentUser);
}
路由器将解析的和静态的数据组合成一个可以访问的属性,如下所示: @Component({...})
class MessageCmp {
constructor(r: ActivatedRoute) {
r.data.subscribe((d => {
console.log('data',d);
});
}
}
当从“/inbox/33/message/44”到“/inbox/33/message/45”时 data {allowReplyAll: true,message: {id: 44,title: ‘Rx Rocks’,…}}
data {allowReplyAll: true,message: {id: 45,title: ‘Angular Rocks’,…}}
queryParams和fragment流与其他特定的某个路由上的可观察对象相反,查询参数和片段可以在多个路由之间共享。 @Component({...})
class MessageCmp {
debug: Observable<string>;
fragment: Observable<string>;
constructor(route: ActivatedRoute) {
this.debug = route.queryParams.map(p => p.debug);
this.fragment = route.fragment;
}
} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |