嗨,安德斯,很好的问题!
我有几乎与您相同的用例,并且想做同样的事情!用户搜索>获取结果>用户导航到结果>用户导航> 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 {}最后一部分 是编写类,该类将控制是否分离,存储,检索和重新连接路由。在我理解旧的 复制/粘贴之前
,我将在这里对机制进行简短的解释。请参考以下代码,了解我正在描述的方法,当然, 代码中 有大量文档。
- 导航时
shouldReuseRoute
会触发。这对我来说有点奇怪,但是如果返回true
,那么它实际上会重用您当前使用的路由,并且不会触发其他任何方法。如果用户正在导航,我只会返回false。 - 如果
shouldReuseRoute
返回false
,则shouldDetach
触发。shouldDetach
确定您是否要存储路线,并返回一个boolean
指示。 这是您应该决定存储/不存储路径的地方 ,我可以通过检查 要 存储的路径数组来完成route.routeConfig.path
,如果path
数组中不存在false,则返回false 。 - 如果
shouldDetach
returntrue
,将store
被触发,这是您存储有关路线的任何信息的机会。无论您做什么,都需要存储,DetachedRouteHandle
因为Angular稍后会使用它来标识已存储的组件。在下面,我将DetachedRouteHandle
和都存储ActivatedRouteSnapshot
到类的局部变量中。
因此,我们已经了解了存储的逻辑,但是导航 到 组件又如何呢?Angular如何决定拦截您的导航并将已存储的导航放置在原处?
- 同样,
shouldReuseRoute
返回后false
,shouldAttach
运行,这是您确定是要重新生成还是使用内存中组件的机会。如果您想重用存储的组件,请返回true
,一切顺利! - 现在,Angular会问您“您要我们使用哪个组件?”,您将通过
DetachedRouteHandle
从返回该组件来进行指示retrieve
。
这几乎就是您需要的所有逻辑!在
reuse-strategy.ts下面的代码中,我还为您提供了一个比较两个对象的漂亮函数。我用它来比较将来的路线
route.params和
route.queryParams已存储的路线。如果所有这些都匹配,我想使用存储的组件,而不是生成一个新组件。但是,如何操作
取决于您!
重用策略
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle } from '@angular/router';interface RouteStorageObject { snapshot: ActivatedRouteSnapshot; handle: DetachedRouteHandle;}export class CustomReuseStrategy implements RouteReuseStrategy { storedRoutes: { [key: string]: RouteStorageObject } = {}; shouldDetach(route: ActivatedRouteSnapshot): boolean { let detach: boolean = true; console.log("detaching", route, "return: ", detach); return detach; } 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; } 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; } } 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]); return this.storedRoutes[route.routeConfig.path].handle; } 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; } 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而不是所有其他组件的组件!



