笔记 | Angular 完成 keep-alive (路由复用)
Angular 的路由复用战略(RouteReuseStrategy)是一种用于优化路由跳转功能和进步用户体会的机制。经过完结RouteReuseStrategy
接口,后能够自界说路由的复用行为,防止不必要的组件毁掉和重建,一起坚持组件的状况。
以下是对Angular路由复用战略的具体介绍:
一、基本概念
RouteReuseStrategy
是 Angular 路由模块供给的一个接口,用于操控路由的复用逻辑。当路由切换时,假如方针路由与当时路由运用相同的组件,经过完结这个接口能够防止组件的从头创立,而是复用现有的组件实例。
二、首要效果
- 防止不必要的组件毁掉和重建:
经过复用组件实例,能够削减 DOM 操作和组件生命周期钩子的调用次数,然后进步运用的功能。
- 坚持组件状况:
在路由切换时,假如组件被复用,那么它的状况(如表单输入、翻滚方位等)也会被保存,然后提高用户体会。
三、处理存在的问题(运用场景)
在项目中,咱们采用了 Cesium 库来构建并加载三维场景。开发进程中注意到一个用户体会上的明显痛点:每逢页面产生跳转并从头回来至 Cesium 场景时,都需求从头进行整个三维场景的加载,这一进程不只延长了用户的等待时间,降低了全体运用的流畅性,还额定增加了系统资源的耗费,对设备的功能提出了更高要求。
为了处理这个问题,方案采纳一种优化战略:将 Cesium 实例化的页面进行 keep-alive 处理。经过这一技术手段,咱们能够保证在页面跳转时,Cesium 场景及其加载的一切资源(如地势数据、模型等)能够坚持活泼状况,而非被毁掉并从头加载。这样,当用户再次拜访该页面时,能够当即看到之前现已加载完结的场景,无需阅历冗长的加载进程,然后明显提高运用的响应速度和用户体会。
四、完结办法
完结中心类:
完结 RouteReuseStrategy
shouldDetach()
是否答应复用路由store()
当路由脱离时会触发,存储路由shouldAttach()
是否答应复原路由retrieve()
获取存储路由shouldReuseRoute()
进入路由触发,是否同一路由时复用路由
流程:
- 运用
shouldDetach()
把路由 /home 设置为答应复用; - 然后经过
store()
将路由快照储存起来; - 路由切换时会触发
shouldReuseRoute()
假如回来为真,(即:再次遇到 /home 路由后表明需求复用路由); - 运用
shouldAttach()
查看是否答应复原; - 最终经过
retrieve()
拿到路由快照并构建组件。
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
type MyDetachedRouteHandle = DetachedRouteHandle | null;
@Injectable()
export class MyReuseStrategy implements RouteReuseStrategy {
private static routeCache = new Map<string, DetachedRouteHandle>();
private static waitDelete: string | null; // 待删去的快照
/**
* 用于删去路由快照
*
* @param {string} url - 需求删去路由的 URL。
* @return {void}
*/
public static deleteRouteSnapshot(url: string): void {
if (url[0] === '/') {
url = url.substring(1);
}
url = url.replace(/\//g, '_');
if (MyReuseStrategy.routeCache.has(url)) {
MyReuseStrategy.routeCache.delete(url);
}
MyReuseStrategy.waitDelete = url;
}
/**
* 用于清空路由快照
*/
public static clearRouteSnapshot(): void {
MyReuseStrategy.routeCache.clear();
MyReuseStrategy.waitDelete = null;
}
/**
* 进入路由时触发,依据将来和当时路由装备和参数的比较确认当时路由是否应该重用。
*
* @param {ActivatedRouteSnapshot} future - 将来的路由快照。
* @param {ActivatedRouteSnapshot} curr - 当时路由快照。
* @return {boolean} 假如应该重用路由,则回来 true,不然回来 false。
*/
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return (
future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) === JSON.stringify(curr.params)
);
}
/**
* 依据路由数据确认路由是否应该别离。
* 表明对一切路由答应复用 假如有路由不想使用能够在这加一些事务逻辑判别,这儿判别路由是否有 keepAlive 数据判别是否复用。
*
* @param {ActivatedRouteSnapshot} route - 要查看别离的路由快照。
* @return {boolean} 假如应该别离路由则回来true,不然回来 false。
*/
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.keepAlive;
}
/**
* 当路由脱离时会触发, 按 path 作为 key 存储路由快照组件当时实例目标
* 假如路由装备为‘’,则呈现Cannot reattach ActivatedRouteSnapshot created from a different route问题
*
* @param {ActivatedRouteSnapshot} route - 用于获取完好路由 URL 的路由快照。
* @param {DetachedRouteHandle} handle - 要存储的路由处理程逻辑。
* @return {void}
*/
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const url = this.getFullRouteUrl(route);
if (MyReuseStrategy.waitDelete && MyReuseStrategy.waitDelete === url) {
// 假如待删去是当时路由,且未存储过则不存储快照
MyReuseStrategy.waitDelete = null;
return;
}
MyReuseStrategy.routeCache.set(url, handle);
}
/**
* 依据 URL 确认是否应该附加路由。
* 若 URL 在缓存中有的都以为答应复原路由
*
* @param {ActivatedRouteSnapshot} route - 要查看的路由快照。
* @return {boolean} 是否应该附加路由。
*/
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
const url = this.getFullRouteUrl(route);
return MyReuseStrategy.routeCache.has(url);
}
/**
* 从缓存中获取快照,若无则回来 null
*
* @param {ActivatedRouteSnapshot} route - 要查看的路由快照
* @return {MyDetachedRouteHandle} MyDetachedRouteHandle
*/
public retrieve(route: ActivatedRouteSnapshot): MyDetachedRouteHandle {
const url = this.getFullRouteUrl(route);
let handle = MyReuseStrategy.routeCache.has(url)
? MyReuseStrategy.routeCache.get(url)
: null;
handle = handle ? handle : null;
return handle;
}
/**
* 依据供给的 ActivatedRouteSnapshot 获取完好的路由 URL。
*
* @param {ActivatedRouteSnapshot} route - 用于生成完好路由 URL 的 ActivatedRouteSnapshot
* @return {string} 过滤、衔接和替换字符后的完好路由URL。
*/
private getFullRouteUrl(route: ActivatedRouteSnapshot): string {
return this.getFullRouteUrlPaths(route).filter(Boolean).join('/').replace(/\//g, '_');
}
/**
* 依据供给的 ActivatedRouteSnapshot 获取完好的路由 URL 的 paths。
*
* @param {ActivatedRouteSnapshot} route - 用于生成完好路由 URL 的 ActivatedRouteSnapshot
* @return {string []}
*/
private getFullRouteUrlPaths(route: ActivatedRouteSnapshot): string[] {
const paths = route.url.map(urlSegment => urlSegment.path);
return route.parent ? [...this.getFullRouteUrlPaths(route.parent), ...paths] : paths;
}
}
将中心类注册到模块中:
在 Angular 运用中,需求将自界说的路由复用战略注入到运用的根模块(通常是 AppModule )中。这能够经过在 providers 数组中增加一个供给器来完结;
...
providers: [
{ provide: RouteReuseStrategy, useClass: MyReuseStrategy }
];
...
路由中高兴 keepAlive:
{
path: 'home',
...
data: { keepAlive: true }
}