当前位置: 首页 > 面试题库 >

如何为Angular 2中的特定路线实施RouteReuseStrategy应该发布

包建义
2023-03-14
问题内容

我有一个Angular2模块,在其中实现了路由,并希望在导航时存储状态。用户应该能够:1.使用searchformula搜索文档2.导航到结果之一3.导航回到searchresult-无需与服务器通信

这可能包括RouteReuseStrategy。问题是:如何实现不应存储该文档?

因此,应该存储路由路径“ documents”的状态,而不应该存储路由路径“ documents /:id”的状态?


问题答案:

嗨,安德斯,很好的问题!

我有几乎与您相同的用例,并且想做同样的事情!用户搜索>获取结果>用户导航到结果>用户导航> BOOM 迅速恢复结果
,但是您不希望存储用户导航到的特定结果。

tl; dr

您需要具有一个类,该类在中实现RouteReuseStrategy并提供您的策略ngModule。如果要在存储路径时进行修改,请修改shouldDetach功能。返回时true,Angular将存储路线。如果要在连接路由时进行修改,请修改shouldAttach功能。当shouldAttach返回true时,Angular将使用存储的路线代替请求的路线。这是一个Plunker供您玩耍。

关于RouteReuseStrategy

通过询问这个问题,您已经了解到RouteReuseStrategy允许您告诉Angular 不要
破坏组件,而实际上是保存它以便以后重新渲染。这很酷,因为它允许:

  • __服务器调用 减少
  • 提高 速度
  • 并且 ,默认情况下,组件以与原始状态相同的状态进行渲染

如果您想暂时离开某个页面,即使用户在其中输入了 很多 文本,那么最后一个页面也很重要。企业应用程序会喜欢这种功能,因为表单数量 过多

这就是我想出的解决问题的方法。如您所说,您需要利用RouteReuseStrategy3.4.1及更高版本中@ angular /
router提供的功能。

去做

首先, 请确保您的项目具有@ angular / router 3.4.1或更高版本。

接下来 ,创建一个文件来存放要实现的类RouteReuseStrategy。我打电话给我reuse- strategy.ts,并将其放在/app文件夹中以进行保管。现在,此类应如下所示:

import { RouteReuseStrategy } from '@angular/router';

export class CustomReuseStrategy implements RouteReuseStrategy {
}

(不必担心您的TypeScript错误,我们将解决所有问题)

通过为您的课程提供 基础知识
完成基础工作app.module。请注意,您尚未编写CustomReuseStrategy,但是应该import从头开始reuse-strategy.ts。也import { RouteReuseStrategy } from '@angular/router';

@NgModule({
    [...],
    providers: [
        {provide: RouteReuseStrategy, useClass: CustomReuseStrategy}
    ]
)}
export class AppModule {
}

最后一部分 是编写类,该类将控制是否分离,存储,检索和重新连接路由。在我理解旧的 复制/粘贴之前
,我将在这里对机制进行简短的解释。请参考以下代码,了解我正在描述的方法,当然, 代码中 有大量文档。

  1. 导航时shouldReuseRoute会触发。这对我来说有点奇怪,但是如果返回true,那么它实际上会重用您当前使用的路由,并且不会触发其他任何方法。如果用户正在导航,我只会返回false。
  2. 如果shouldReuseRoute返回false,则shouldDetach触发。shouldDetach确定您是否要存储路线,并返回一个boolean指示。 这是您应该决定存储/不存储路径的地方 ,我可以通过检查 存储的路径数组来完成route.routeConfig.path,如果path数组中不存在false,则返回false 。
  3. 如果shouldDetachreturn true,将store被触发,这是您存储有关路线的任何信息的机会。无论您做什么,都需要存储,DetachedRouteHandle因为Angular稍后会使用它来标识已存储的组件。在下面,我将DetachedRouteHandle和都存储ActivatedRouteSnapshot到类的局部变量中。

因此,我们已经了解了存储的逻辑,但是导航 组件又如何呢?Angular如何决定拦截您的导航并将已存储的导航放置在原处?

  1. 同样,shouldReuseRoute返回后falseshouldAttach运行,这是您确定是要重新生成还是使用内存中组件的机会。如果您想重用存储的组件,请返回true,一切顺利!
  2. 现在,Angular会问您“您要我们使用哪个组件?”,您将通过DetachedRouteHandle从返回该组件来进行指示retrieve

这几乎就是您需要的所有逻辑!在reuse-strategy.ts下面的代码中,我还为您提供了一个比较两个对象的漂亮函数。我用它来比较将来的路线route.paramsroute.queryParams已存储的路线。如果所有这些都匹配,我想使用存储的组件,而不是生成一个新组件。但是,如何操作
取决于您!

重用策略

/**
 * reuse-strategy.ts
 * by corbfon 1/6/17
 */

import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle } from '@angular/router';

/** Interface for object which can store both: 
 * An ActivatedRouteSnapshot, which is useful for determining whether or not you should attach a route (see this.shouldAttach)
 * A DetachedRouteHandle, which is offered up by this.retrieve, in the case that you do want to attach the stored route
 */
interface RouteStorageObject {
    snapshot: ActivatedRouteSnapshot;
    handle: DetachedRouteHandle;
}

export class CustomReuseStrategy implements RouteReuseStrategy {

    /** 
     * Object which will store RouteStorageObjects indexed by keys
     * The keys will all be a path (as in route.routeConfig.path)
     * This allows us to see if we've got a route stored for the requested path
     */
    storedRoutes: { [key: string]: RouteStorageObject } = {};

    /** 
     * Decides when the route should be stored
     * If the route should be stored, I believe the boolean is indicating to a controller whether or not to fire this.store
     * _When_ it is called though does not particularly matter, just know that this determines whether or not we store the route
     * An idea of what to do here: check the route.routeConfig.path to see if it is a path you would like to store
     * @param route This is, at least as I understand it, the route that the user is currently on, and we would like to know if we want to store it
     * @returns boolean indicating that we want to (true) or do not want to (false) store that route
     */
    shouldDetach(route: ActivatedRouteSnapshot): boolean {
        let detach: boolean = true;
        console.log("detaching", route, "return: ", detach);
        return detach;
    }

    /**
     * Constructs object of type `RouteStorageObject` to store, and then stores it for later attachment
     * @param route This is stored for later comparison to requested routes, see `this.shouldAttach`
     * @param handle Later to be retrieved by this.retrieve, and offered up to whatever controller is using this class
     */
    store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
        let storedRoute: RouteStorageObject = {
            snapshot: route,
            handle: handle
        };

        console.log( "store:", storedRoute, "into: ", this.storedRoutes );
        // routes are stored by path - the key is the path name, and the handle is stored under it so that you can only ever have one object stored for a single path
        this.storedRoutes[route.routeConfig.path] = storedRoute;
    }

    /**
     * Determines whether or not there is a stored route and, if there is, whether or not it should be rendered in place of requested route
     * @param route The route the user requested
     * @returns boolean indicating whether or not to render the stored route
     */
    shouldAttach(route: ActivatedRouteSnapshot): boolean {

        // this will be true if the route has been stored before
        let canAttach: boolean = !!route.routeConfig && !!this.storedRoutes[route.routeConfig.path];

        // this decides whether the route already stored should be rendered in place of the requested route, and is the return value
        // at this point we already know that the paths match because the storedResults key is the route.routeConfig.path
        // so, if the route.params and route.queryParams also match, then we should reuse the component
        if (canAttach) {
            let willAttach: boolean = true;
            console.log("param comparison:");
            console.log(this.compareObjects(route.params, this.storedRoutes[route.routeConfig.path].snapshot.params));
            console.log("query param comparison");
            console.log(this.compareObjects(route.queryParams, this.storedRoutes[route.routeConfig.path].snapshot.queryParams));

            let paramsMatch: boolean = this.compareObjects(route.params, this.storedRoutes[route.routeConfig.path].snapshot.params);
            let queryParamsMatch: boolean = this.compareObjects(route.queryParams, this.storedRoutes[route.routeConfig.path].snapshot.queryParams);

            console.log("deciding to attach...", route, "does it match?", this.storedRoutes[route.routeConfig.path].snapshot, "return: ", paramsMatch && queryParamsMatch);
            return paramsMatch && queryParamsMatch;
        } else {
            return false;
        }
    }

    /** 
     * Finds the locally stored instance of the requested route, if it exists, and returns it
     * @param route New route the user has requested
     * @returns DetachedRouteHandle object which can be used to render the component
     */
    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {

        // return null if the path does not have a routerConfig OR if there is no stored route for that routerConfig
        if (!route.routeConfig || !this.storedRoutes[route.routeConfig.path]) return null;
        console.log("retrieving", "return: ", this.storedRoutes[route.routeConfig.path]);

        /** returns handle when the route.routeConfig.path is already stored */
        return this.storedRoutes[route.routeConfig.path].handle;
    }

    /** 
     * Determines whether or not the current route should be reused
     * @param future The route the user is going to, as triggered by the router
     * @param curr The route the user is currently on
     * @returns boolean basically indicating true if the user intends to leave the current route
     */
    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
        console.log("deciding to reuse", "future", future.routeConfig, "current", curr.routeConfig, "return: ", future.routeConfig === curr.routeConfig);
        return future.routeConfig === curr.routeConfig;
    }

    /** 
     * This nasty bugger finds out whether the objects are _traditionally_ equal to each other, like you might assume someone else would have put this function in vanilla JS already
     * One thing to note is that it uses coercive comparison (==) on properties which both objects have, not strict comparison (===)
     * Another important note is that the method only tells you if `compare` has all equal parameters to `base`, not the other way around
     * @param base The base object which you would like to compare another object to
     * @param compare The object to compare to base
     * @returns boolean indicating whether or not the objects have all the same properties and those properties are ==
     */
    private compareObjects(base: any, compare: any): boolean {

        // loop through all properties in base object
        for (let baseProperty in base) {

            // determine if comparrison object has that property, if not: return false
            if (compare.hasOwnProperty(baseProperty)) {
                switch(typeof base[baseProperty]) {
                    // if one is object and other is not: return false
                    // if they are both objects, recursively call this comparison function
                    case 'object':
                        if ( typeof compare[baseProperty] !== 'object' || !this.compareObjects(base[baseProperty], compare[baseProperty]) ) { return false; } break;
                    // if one is function and other is not: return false
                    // if both are functions, compare function.toString() results
                    case 'function':
                        if ( typeof compare[baseProperty] !== 'function' || base[baseProperty].toString() !== compare[baseProperty].toString() ) { return false; } break;
                    // otherwise, see if they are equal using coercive comparison
                    default:
                        if ( base[baseProperty] != compare[baseProperty] ) { return false; }
                }
            } else {
                return false;
            }
        }

        // returns true only after false HAS NOT BEEN returned through all loops
        return true;
    }
}

行为

此实现将用户访问的每个唯一路由准确地存储在路由器上一次。这将继续添加到站点上整个用户会话中存储在内存中的组件。如果您想限制您存储的路线,则可以使用该shouldDetach方法。它控制着您保存的路由。

假设您的用户从首页中搜索了一些内容,然后将其导航到该路径search/:term,该路径可能显示为www.yourwebsite.com/search/thingsearchedfor。搜索页面包含一堆搜索结果。您想存储这条路线,以防他们想回来!现在,他们点击一个搜索结果,并获得导航到view/:resultId,你
希望店,看到他们很可能会出现一次。完成上述实现后,我只需更改shouldDetach方法即可!可能是这样的:

首先, 让我们创建一个要存储的路径数组。

private acceptedRoutes: string[] = ["search/:term"];

现在,shouldDetach我们可以route.routeConfig.path对照数组检查。

shouldDetach(route: ActivatedRouteSnapshot): boolean {
    // check to see if the route's path is in our acceptedRoutes array
    if (this.acceptedRoutes.indexOf(route.routeConfig.path) > -1) {
        console.log("detaching", route);
        return true;
    } else {
        return false; // will be "view/:resultId" when user navigates to result
    }
}

由于Angular将仅存储路线的一个实例,因此该存储将是轻量级的,我们将仅存储位于search/:term而不是所有其他组件的组件!



 类似资料:
  • 我在C编程,但我只使用pthread. h,没有升压或C 11线程。 所以我试图使用线程,但是基于我之前的一个问题(链接),这似乎是不可行的,因为线程在完成任务后立即终止,使用线程池实现的一个更普遍的原因是通过以下方式减少线程创建开销为多个任务重用这些线程。 那么,在C中实现这一点的唯一其他方法是使用fork()并创建从主进程到子进程的管道吗?或者有没有一种方法可以在线程和它们的父线程之间设置一个

  • 问题内容: 我想知道在angular2中设置可配置模块的最佳方法是什么。在angular1中,这通常是通过提供程序完成的。在对它们进行了相当多的更改之后,您将如何将配置参数传递给可重用的ng2模块/指令/组件? 一个NG1例子: 这个问题基本上与此问题相同,但针对的是angular2。 问题答案: 有几种配方,可以单独使用或一起使用。 通常需要提供服务来提供键/值形式的必要配置。 可能有多个配置服

  • 问题内容: 我正在使用Angular2开发NodeJS应用程序。在我的应用程序中,我有一个主页和搜索页面。对于主页,我有一个将为 localhost:3000 /* 呈现的HTML页面,并且从主页用户导航到 搜索, 即 我由 angular2路由 处理的 localhost:3000 / search 页面。 * 我没有搜索页面的页面,其视图由angular2呈现。但是当我直接点击 localho

  • 有没有书,学习网站,开源羡慕,视频教材推荐。 本人具备5年的前端基础

  • 问题内容: 我想删除多条线图中的特定线。贝娄是一个给我的例子,这对我来说还不够,因为它仅删除最后绘制的线条,而不删除我要删除的线条。我怎样才能做到这一点?如何在整个程序中寻址特定行(按名称,编号,参考)并删除该行? 问题答案: 几乎所有的绘图功能都返回对先前创建的对象的引用: 如果您有参考文献,则可以通过 (doc)函数ex删除艺术家:

  • 问题内容: 问题是由于火车数据大小,我的火车数据无法放入RAM。因此,我需要一种方法,该方法首先在整个火车数据集上构建一棵树,然后计算残差来构建另一棵树,依此类推(就像梯度增强树一样)。显然,如果我在某个循环中调用-这将无济于事,因为在这种情况下,它只会为每个批次重建整个模型。 问题答案: 免责声明:我也是xgboost的新手,但我想我已经明白了。 在进行第一批训练后,请尝试保存模型。然后,在连续