共计 3504 个字符,预计需要花费 9 分钟才能阅读完成。
关于路由复用策略网上的文章很多,大多是讲如何实现 tab 标签切换历史数据,至于如何复用的原理讲的都比较朦胧,代码样例也很难适用各种各样的路由配置,比如懒加载模式下多级嵌套路由出口网上的大部分代码都会报错。我希望能通过这篇文章把如何复用路由的原理讲明白,让小伙伴能明明白白的实用路由复用策略,文字中有不详实和错误的地方欢迎小伙伴批评指正
对路由复用策略的理解
路由复用策略的是对路由的父级相同节点的组件实例的复用,我们平时看到的多级嵌套路由切换时上层路由出口的实例并不会从新实例化就是因为 angular 默认的路由复用策略在起作用,而我们从写路由复用策略能实现很多事情,其中之一就是实现历史路由状态(数据)的存储,即 jquery 时代的 tab 页签和 iframe 实现操作历史的切换。我一开始认为路由复用策略就是对历史路由数据的复用策略, 这个错误的观念导致我对路由复用策略接口方法理解起来异常困难,不知小伙伴和我犯没犯同样的错误。观念正确了,下面就理解起来比较方便了,写路由复用策略也就比较顺手了。
下面是 angular 默认路由复用策略,每切换一下路由,下面代码都再默默的执行。
export class DefaultRouteReuseStrategy {
shouldDetach(route) {return false;}
store(route, detachedTree) {}
shouldAttach(route) {return false;}
retrieve(route) {return null;}
shouldReuseRoute(future, curr) {
return future.routeConfig === curr.routeConfig;
}
}
每个活动路由是一棵树,每个节点都有一个 ActivatedRouteSnapshot,root 节点是 RouterModule.forRoot(Routes)Routes 之上的一个默认路由,也无法配置
路由复用策略解析
路由复用策略方法调用顺序
shouldReuseRoute(future, curr)
retrieve(route)
shouldDetach(route)
store(route, detachedTree)
shouldAttach(route)
retrieve, 取决一上一步的返回值
store(route, detachedTree), 取决第五步
shouldReuseRoute
shouldReuseRoute() 决定是否复用路由,根据切换的前后路由的节点层级依次调用,返回值为 true 时表示当前节点层级路由复用,然后继续下一路由节点调用,入参为切换的下一级路由(子级)的前后路由,返回值为 false 时表示不在复用路由,并且不再继续调用此方法(当前路由不再复用,其子级路由也不会复用,所以不需要再询问下去),root 路由节点调用一次,非 root 路由节点调用两次这个方法,第一次比较父级节点,第二次比较当前节点,
retrieve
retrieve() 接上一步奏,当当前层级路由不需要复用的时候,调用一下 retrieve 方法,其子级路由也会调用一下 retrieve 方法,如果返回的是 null,那么当前路由对应的组件会实例化,这种行为一直持续到末级路由。
shouldDetach
shouldDetach 是对上一路由的数据是否实现拆离,其调用开始是当前层级路由不需要复用的时候,即 shouldReuseRoute() 返回 false 的时候,如果这时候反回 false,将继续到上一路由的下一层级调用 shouldDetach, 直到返回 true 或者是最末级路由后才结束对 shouldDetach 的调用,当返回 true 时就调用一次 store 方法,请看下一步奏
store
store 存储路分离出来的上一路由的数据,当 shouldDetach 返回 true 时调用一次,存储应该被分离的那一层的路由的 DetachedRouteHandle。注意:无论路由树上多个含有组件 component 路由节点,能分离出来的只能有一个,被存储的也只能有一个,感觉这种机制对使用场景有很大限制。
shouldAttach
shouldAttach 是对当前路由的数据是否实现恢复(附加回来),其调用开始是当前层级路由不需要复用的时候,即 shouldReuseRoute() 返回 false 的时候,这和 shouldDetach 的调用时机很像,但是,并不是所有的路由层级都是有组件实例的,只有包含 component 的 route 才会触发 shouldAttach,如果反回 false,将继续到当前路由的下一带有 component 的路由层级调用 shouldAttach, 直到返回 true 或者是最末级路由后才结束对 shouldAttach 的调用,当返回 true 时就调用一次 retrieve 方法,如果 retrieve 方法去获取一下当前路由的 DetachedRouteHandle, 返回一个 DetachedRouteHandle,就再调用一次 store, 再保存一下 retrieve 返回的 DetachedRouteHandle。注意注意:无论路由树上多个含有组件 component 路由节点,能恢复数据的只能有一个节点,这和 shouldDetach 是一个套路,对使用场景有很大限制。
总结·这个还是实验性的路由复用策略还是不够强大
路由复用策略这种调用机制对使用场景限制很大,比如多级路由出口嵌套就无法实现路由数据缓存。因为多级路由出口嵌套的应用切换路由时,前后路由会包含多个带 component 的路由节点,而每次对路由的存储和恢复只能存储和恢复某一个节点的 component 的 DetachedRouteHandle,其他路由节点上的 component 就是被从新实例化。明白这一点后我就放弃了想写一个可以适用任何场景的路由复用策略的想法,如果有小伙伴能解决好这一业务场景,欢迎赐教。
如果这个路由复用策略可以存储一个路由上多个节点的 DetachedRouteHandle,和恢复多个节点的 DetachedRouteHandle,应该能解决上面是的多级路由出口嵌套场景,但不知道会不会带来别的问题。
一个路由复用策略用例
下面贴一个路由复用策略用例,应该是满足大部分人的业务要求,注意事项:只能是末级路由的缓存,且路由切换的时候路由节点上的 component 不能超过两个。
import {ActivatedRouteSnapshot, DetachedRouteHandle, Route, RouteReuseStrategy} from “@angular/router”;
export class CustomerReuseStrategy implements RouteReuseStrategy {
static handlers: Map<Route, DetachedRouteHandle> = new Map();
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return !route.firstChild;
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!CustomerReuseStrategy.handlers.has(route.routeConfig);
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) {
return curr.routeConfig === future.routeConfig;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return CustomerReuseStrategy.handlers.get(route.routeConfig);
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
CustomerReuseStrategy.handlers.set(route.routeConfig, handle);
}
}
很精简,但是很好用,小伙伴可以根据自己的业务逻辑进行改造。
如果感觉这篇文章对你有帮助,请点个赞吧 ????????????????????????????????????????????????????????????????????????