gpt4 book ai didi

Angular RouteReuseStrategy 后退按钮/交叉模块

转载 作者:行者123 更新时间:2023-12-04 17:14:58 27 4
gpt4 key购买 nike

关于我的应用程序(Angular 12)的信息:

  • 由 3 个模块组成,每个模块都有一个带有列表的概览页面和一些详细信息页面
  • 每条路线都有一个区域标签,所以我知道用户在哪个模块中导航

  • 所以我想为以下行为实现 Angular 的 RouteReuseStrategy:
  • 每当用户从列表 -> 详细信息页面导航并使用后退按钮时,应重用列表组件(检测后退按钮触发器)
  • 每当用户从不同的模块/区域导航到列表组件时,不应重用列表组件
  • 每当用户从详细信息导航到另一个详细信息页面时,应该重用详细信息组件(默认行为?)
  • 每当用户通过导航到另一个模块或注销而离开模块时,应清除/销毁存储的组件

  • 现状:
  • 我实现了一个自定义的 RouteReuseStrategy,它可以工作并且列表组件被重用 ✓
  • 只有滚动位置没有恢复,这个需要单独检查✕

  • 我想检查路线内的区域标签,但 ActivatedRouteSnapshots 是空的 ✕
  • 检测后退按钮按下,但事件经常触发,如果我实现一个基本的后退标志,它会中断✕

  • 缺什么?
  • 检测返回按钮导航并修改组件的复用
  • 检测路由属于哪个模块以修改重用或清理存储的组件

  • 代码:
    示例路线 在模块 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 和当前快照的日志 (只有网址有用)
    Current & Future Route show AppComponent
    为什么是这样 应用组件 而不是 详情 ListAComponent ?
    也许这就是数据为空的原因?
    我需要获得正确的路由/组件来访问 areaCategory 以实现所需的行为。
    根据这里的要求是一个简单的 stackblitz用我的设置
    如果我错过了什么,请告诉我,非常感谢您的帮助

    最佳答案

    这尊重你的条件

  • 每当用户从列表 -> 详细信息页面导航并使用后退按钮时,应重用列表组件(检测后退按钮触发器)。 是的。假设您没有 list -> detail -> list导航
  • 每当用户从不同的模块/区域导航到列表组件时,不应重用列表组件。 是的。假设不同的区域不能有相同的areaCategory标签
  • 每当用户从详细信息导航到另一个详细信息页面时,应该重用详细信息组件(默认行为?)。
  • 每当用户通过导航到另一个模块或注销而离开模块时,应清除/销毁存储的组件 是的,同 2。

  • 我给你添加了一些额外的评论和图表来理解 RouteReuseStrategy调用这将更清楚如何使用它。
    遵循图表和伪代码,显示了 Angular 核心如何使用该策略(这是基于我的观察,我没有找到官方文档):
    enter image description here
    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;
    }
    }
    }
    当然,这是一个例子。 getRouteHandlercreateRouteFromHandler仅作为示例介绍,不区分路由组件、路由实例和路由快照。
    @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/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com