作者热门文章
- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有一个 Angular 2 模块,我在其中实现了路由,并希望在导航时存储状态。
用户应该能够:
RouteReuseStrategy
.
最佳答案
嘿安德斯,好问题!
我有和你几乎一样的用例,并且想做同样的事情!用户搜索 > 获取结果 > 用户导航到结果 > 用户返回 > 繁荣 快速返回结果,但您不想存储用户导航到的特定结果。
tl;博士
您需要有一个实现 RouteReuseStrategy
的类并在 ngModule
中提供您的策略.如果要修改路由存储时,修改shouldDetach
功能。当它返回时 true
, Angular 存储路由。如果要在附加路由时修改,修改shouldAttach
功能。当shouldAttach
返回 true,Angular 将使用存储的路由代替请求的路由。这是一个 Plunker供你玩耍。
关于RouteReuseStrategy
通过问这个问题,您已经了解 RouteReuseStrategy 允许您告诉 Angular 不要销毁组件,而实际上是保存它以供以后重新渲染。这很酷,因为它允许:
RouteReuseStrategy
由 @angular/router 在 3.4.1 及更高版本中提供。
RouteReuseStrategy
的类.我调用我的
reuse-strategy.ts
并将其放入
/app
用于保管的文件夹。现在,这个类应该是这样的:
import { RouteReuseStrategy } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
}
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不存在于数组中。 shouldDetach
返回 true
, store
被解雇,这是您存储您想要的有关路线的任何信息的机会。无论您做什么,您都需要存储 DetachedRouteHandle
因为这是 Angular 稍后用来识别您存储的组件的内容。下面,我存储了 DetachedRouteHandle
和 ActivatedRouteSnapshot
进入我类(class)的本地变量。 shouldReuseRoute
之后已返回 false
, shouldAttach
运行,这是您确定是否要重新生成或使用内存中的组件的机会。如果要重用已存储的组件,请返回 true
一切顺利! DetachedRouteHandle
来指明这一点。来自 retrieve
. reuse-strategy.ts
的代码中,下面,我还给你留下了一个漂亮的函数,可以比较两个对象。我用它来比较 future 路线的
route.params
和
route.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
}
}
search/:term
的组件。而不是所有其他人!
关于javascript - 如何为 Angular 2 中的特定路由实现 RouteReuseStrategy shouldDetach,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41280471/
我是一名优秀的程序员,十分优秀!