关于我的应用程序(Angular 12)的信息:
所以我想为以下行为实现 Angular 的 RouteReuseStrategy:
现状:
缺什么?
代码:
示例路线 在模块 A
{
path: 'lista',
component: ListAComponent,
data: {
title: 'List overview',
areaCategory: AreaCategory.A,
reuseRoute: true,
},
},
{
path: 'lista/:id',
component: DetailAComponent,
data: {
title: 'Detail',
areaCategory: AreaCategory.A,
reuseRoute: false,
},
},
示例路线 模块 B{
path: 'listb',
component: ListBComponent,
data: {
title: 'List overview',
areaCategory: AreaCategory.B,
reuseRoute: true,
},
},
{
path: 'listb/:id',
component: DetailBComponent,
data: {
title: 'Detail',
areaCategory: AreaCategory.B,
reuseRoute: false,
},
},
app.module.ts providers: [
{
provide: RouteReuseStrategy,
useClass: CustomReuseRouteStrategy,
}
],
全局应该没问题,还是我需要将它移动到 3 个模块中的每一个?ReuseRouteStrategy
@Injectable()
export class CustomReuseRouteStrategy implements RouteReuseStrategy {
private handlers: { [key: string]: DetachedRouteHandle } = {};
// Detect Backbutton-navigation
back = false;
constructor(location: LocationStrategy) {
location.onPopState(() => {
this.back = true;
});
}
shouldDetach(route: ActivatedRouteSnapshot): boolean {
if (!route.routeConfig || route.routeConfig.loadChildren) {
return false;
}
// Check route.data.reuse whether this route should be re used or not
let shouldReuse = false;
if (
route.routeConfig.data &&
route.routeConfig.data.reuseRoute &&
typeof route.routeConfig.data.reuseRoute === 'boolean'
) {
shouldReuse = route.routeConfig.data.reuseRoute;
}
return shouldReuse;
}
store(route: ActivatedRouteSnapshot, handler: DetachedRouteHandle): void {
if (handler) {
this.handlers[this.getUrl(route)] = handler;
}
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
if (!this.back) {
return false;
}
return !!this.handlers[this.getUrl(route)];
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!this.back || !route.routeConfig || route.routeConfig.loadChildren) {
return null;
}
//this.back = false; -> does not work fires to often
return this.handlers[this.getUrl(route)];
}
shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
/** We only want to reuse the route if the data of the route config contains a reuse true boolean */
let reUseUrl = false;
if (future.routeConfig && future.routeConfig.data && typeof future.routeConfig.data.reuseRoute === 'boolean') {
reUseUrl = future.routeConfig.data.reuseRoute;
}
//const defaultReuse = future.routeConfig === current.routeConfig; -> used for navigating to same component but routeConfigs are empty therefore always match?
return reUseUrl;
}
private getUrl(route: ActivatedRouteSnapshot): string {
if (route.routeConfig) {
const url = route.routeConfig.path;
return url;
}
}
clearHandles() {
for (const key in this.handlers) {
if (this.handlers[key]) {
this.destroyHandle(this.handlers[key]);
}
}
this.handlers = {};
}
private destroyHandle(handle: DetachedRouteHandle): void {
const componentRef: ComponentRef<any> = handle['componentRef'];
if (componentRef) {
componentRef.destroy();
}
}
}
我注意到 _routerState ActivatedRouteSnapshot 中包含 url,可用于区分模块,但我宁愿从路由数据中检查 areaCategory 但奇怪的是,shouldReuseRoute 方法中的 future 和当前 ActivatedRouteSnapshots 大多为空我也不确定是否使用像 _routerState 这样的内部值,因为我听说这些不是固定的,可以随时更改
空 future 和当前快照的日志 (只有网址有用)
为什么是这样应用组件 而不是 详情 或 ListAComponent ?
也许这就是数据为空的原因?
我需要获得正确的路由/组件来访问 areaCategory 以实现所需的行为。
根据这里的要求是一个简单的 stackblitz用我的设置
如果我错过了什么,请告诉我,非常感谢您的帮助
最佳答案
这尊重你的条件
list -> detail -> list
导航 areaCategory
标签 我给你添加了一些额外的评论和图表来理解
RouteReuseStrategy
调用这将更清楚如何使用它。遵循图表和伪代码,显示了 Angular 核心如何使用该策略(这是基于我的观察,我没有找到官方文档):
transition(current, future) {
if (shouldReuseRoute(future, current)) {
// No navigation is performed, same route is recycled
return current;
} else {
if (shouldDetach(current)) {
// If not reused and shouldDetach() == true then store
store(current, getRouteHandler(current));
}
if (shouldAttach(future)) {
// If not reused and shouldAttach() == true then retrieve
return createRouteFromHandler(retrieve(future));
} else {
// If shouldAttach() == false do not recycle
return future;
}
}
}
当然,这是一个例子。 getRouteHandler
和 createRouteFromHandler
仅作为示例介绍,不区分路由组件、路由实例和路由快照。@Injectable()
export class CustomReuseRouteStrategy implements RouteReuseStrategy {
private handlers: { [key: string]: DetachedRouteHandle } = {};
clearHandlers() {
Object.keys(this.handlers).forEach(h => {
// https://github.com/angular/angular/issues/15873
(h as any).componentRef.destroy();
})
this.handlers = {};
}
areSameArea(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
return future.routeConfig.data && current.routeConfig.data
&& future.routeConfig.data.areaCategory === current.routeConfig.data.areaCategory;
}
/**
* This function decides weather the current route should be kept.
* If this function returns `true` nor attach or detach procedures are called
* (hence none of shouldDetach, shouldAttach, store, retrieve). If this function
* returns `false` an attach/detach procedure is initiated.
*/
shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
console.log('shouldReuseRoute', future, current);
if (!this.areSameArea(future, current)) {
// Changed area, clear the cache
this.clearHandlers();
}
return this.getUrl(future) === this.getUrl(current);
}
/**
* DETACH PROCEDURE: if performing a detach, this function is called, if returns
* `true` then store is called, to store the current context.
*/
shouldDetach(route: ActivatedRouteSnapshot): boolean {
console.log('shouldDetach', route);
// We always detach them (you never mentioned pages that are not recycled
// by default)
return true;
}
store(route: ActivatedRouteSnapshot, handler: DetachedRouteHandle): void {
console.log('store', route, this.getUrl(route));
if (!handler && this.getUrl(route)) return;
this.handlers[this.getUrl(route)] = handler;
}
/**
* ATTACH PROCEDURE: if performing an attach, this function is called, if returns
* `true` then retrieve is called, to store the current context.
*/
shouldAttach(route: ActivatedRouteSnapshot): boolean {
console.log('shouldAttach', route);
return !!this.handlers[this.getUrl(route)];
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
console.log('retrieve', route, this.getUrl(route));
return this.getUrl(route) && this.handlers[this.getUrl(route)];
}
private getUrl(route: ActivatedRouteSnapshot): string {
// todo : not sure this behaves properly in case of parametric routes
return route.routeConfig && route.routeConfig.path;
}
}
关于Angular RouteReuseStrategy 后退按钮/交叉模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68902912/