라우팅을 구현 한 Angular 2 모듈이 있으며 탐색 할 때 상태를 저장하고 싶습니다. 사용자는 다음을 수행 할 수 있어야합니다. 1. 검색 공식을 사용하여 문서 검색 2. 결과 중 하나로 이동 3. 검색 결과로 다시 이동-서버와 통신하지 않고
이는 RouteReuseStrategy를 포함하여 가능합니다. 질문은 문서가 저장되지 않도록 구현하는 방법입니다.
그래서 경로 경로 “documents”의 상태를 저장해야하고 경로 경로 “documents / : id” ‘상태를 저장하지 않아야합니까?
답변
안녕하세요 Anders, 좋은 질문입니다!
나는 당신과 거의 같은 사용 사례를 가지고 있으며 같은 일을하고 싶었습니다! 사용자 검색> 결과 가져 오기> 사용자가 결과로 이동> 사용자가 뒤로 이동> BOOM 결과로 빠르게 돌아가 지만 사용자가 탐색 한 특정 결과를 저장하고 싶지 않습니다.
tl; dr
RouteReuseStrategy
.NET Framework에서 전략 을 구현 하고 제공 하는 클래스가 있어야 합니다 ngModule
. 경로가 저장 될 때 수정하려면 shouldDetach
기능을 수정하십시오 . 반환 true
되면 Angular는 경로를 저장합니다. 루트가 부착 된 시점을 수정하려면 shouldAttach
기능을 수정하십시오 . shouldAttach
true를 반환 하면 Angular는 요청 된 경로 대신 저장된 경로를 사용합니다. 여기 에 플레이 할 수 있는 Plunker 가 있습니다.
RouteReuseStrategy 정보
이 질문을 통해 RouteReuseStrategy를 사용하면 Angular 가 구성 요소를 파괴 하지 않고 실제로 나중에 다시 렌더링하기 위해 저장 하도록 지시 할 수 있음을 이미 이해했습니다 . 다음을 허용하기 때문에 멋집니다.
- 서버 호출 감소
- 증가 된 속도
- 그리고 구성 요소는 기본적으로 남은 상태로 렌더링됩니다.
마지막 페이지는 사용자가 페이지에 많은 텍스트를 입력 했음에도 불구하고 일시적으로 페이지를 떠나려는 경우에 중요 합니다. 과도한 양의 양식 때문에 엔터프라이즈 응용 프로그램은이 기능을 좋아할 것입니다 !
이것이 제가 문제를 해결하기 위해 생각 해낸 것입니다. 말했듯이 RouteReuseStrategy
버전 3.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
하고,이 경우는 false를 반환path
배열에 존재하지 않습니다. - 경우
shouldDetach
반환true
,store
당신은 당신이 경로에 대해 원하는 정보를 모두 저장할 수있는 기회 인, 발생합니다. 무엇을 하든지간에DetachedRouteHandle
Angular가 나중에 저장된 구성 요소를 식별하는 데 사용 하는 것이기 때문에 를 저장해야합니다 . 다음, 나는 모두 저장DetachedRouteHandle
하고ActivatedRouteSnapshot
내 클래스에 변수 지역에 있습니다.
그래서 우리는 저장 로직을 보았지만 컴포넌트로 이동 하는 것은 어떨까요? Angular는 내비게이션을 가로 채서 저장된 내비게이션을 제자리에두기로 결정합니까?
- 다시, 후
shouldReuseRoute
돌아왔다false
,shouldAttach
당신은 재생 또는 메모리에있는 구성 요소를 사용할지 여부를 알아낼 수있는 기회 인 실행합니다. 저장된 구성 요소를 재사용true
하려면 돌아 가면됩니다 . - 해당 구성 요소의 반환에 의해 표시되는, “당신은 우리가 사용하려는 않는 구성 요소?”를 묻습니다 이제 각도
DetachedRouteHandle
에서retrieve
.
그것은 당신이 필요로하는 거의 모든 논리입니다! 아래의에 대한 코드에서 reuse-strategy.ts
두 개체를 비교할 수있는 멋진 함수도 남겼습니다. 나는 미래 경로의 비교에 사용 route.params
하고 route.queryParams
저장된 하나 개의과. 모두 일치하면 새 구성 요소를 생성하는 대신 저장된 구성 요소를 사용하고 싶습니다. 그러나 어떻게하는지는 당신에게 달려 있습니다!
재사용 전략 .ts
/**
* 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
다른 모든 인스턴스 가 아닌에있는 구성 요소 만 저장합니다 !
추가 링크
아직 문서가 많지는 않지만 여기에 몇 가지 링크가 있습니다.
Angular 문서 : https://angular.io/docs/ts/latest/api/router/index/RouteReuseStrategy-class.html
의 nativescript – 각도의 기본 구현 RouteReuseStrategy : https://github.com/NativeScript/nativescript-angular/blob/cb4fd3a/nativescript-angular/router/ns-route-reuse-strategy.ts
답변
받아 들여지는 대답에 겁 먹지 마십시오. 이것은 매우 간단합니다. 여기에 필요한 빠른 답변이 있습니다. 나는 그것이 매우 세부적으로 가득 차 있기 때문에 적어도 받아 들여지는 대답을 읽는 것이 좋습니다.
이 솔루션은 허용되는 답변과 같은 매개 변수 비교를 수행하지 않지만 경로 집합을 저장하는 데는 잘 작동합니다.
app.module.ts 가져 오기 :
import { RouteReuseStrategy } from '@angular/router';
import { CustomReuseStrategy, Routing } from './shared/routing';
@NgModule({
//...
providers: [
{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy },
]})
shared / routing.ts :
export class CustomReuseStrategy implements RouteReuseStrategy {
routesToCache: string[] = ["dashboard"];
storedRouteHandles = new Map<string, DetachedRouteHandle>();
// Decides if the route should be stored
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return this.routesToCache.indexOf(route.routeConfig.path) > -1;
}
//Store the information for the route we're destructing
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.storedRouteHandles.set(route.routeConfig.path, handle);
}
//Return true if we have a stored route object for the next route
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return this.storedRouteHandles.has(route.routeConfig.path);
}
//If we returned true in shouldAttach(), now return the actual route data for restoration
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return this.storedRouteHandles.get(route.routeConfig.path);
}
//Reuse the route if we're going to and from the same route
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
}
답변
받아 들여지는 답변 (Corbfon)과 Chris Fremgen의 짧고 간단한 설명 외에도 재사용 전략을 사용해야하는 경로를 처리하는 더 유연한 방법을 추가하고 싶습니다.
두 답변 모두 배열에 캐시하려는 경로를 저장 한 다음 현재 경로 경로가 배열에 있는지 확인합니다. 이 검사는 shouldDetach
방법 으로 수행됩니다 .
경로 이름을 변경하려면 CustomReuseStrategy
클래스 에서 경로 이름도 변경해야하므로이 접근 방식은 유연하지 않습니다 . 우리는 그것을 변경하는 것을 잊거나 우리 팀의 다른 개발자가의 존재를 알지도 못하는 경로 이름을 변경하기로 결정할 수 있습니다 RouteReuseStrategy
.
캐시하려는 경로를 배열에 저장하는 대신 객체 를 RouterModule
사용하여 직접 표시 할 수 있습니다 data
. 이렇게하면 경로 이름을 변경하더라도 재사용 전략이 계속 적용됩니다.
{
path: 'route-name-i-can-change',
component: TestComponent,
data: {
reuseRoute: true
}
}
그리고 shouldDetach
방법에서 우리는 그것을 사용합니다.
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute === true;
}
답변
지연로드 된 모듈에서 Chris Fremgen의 전략을 사용하려면 CustomReuseStrategy 클래스를 다음과 같이 수정합니다.
import {ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy} from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
routesToCache: string[] = ["company"];
storedRouteHandles = new Map<string, DetachedRouteHandle>();
// Decides if the route should be stored
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return this.routesToCache.indexOf(route.data["key"]) > -1;
}
//Store the information for the route we're destructing
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.storedRouteHandles.set(route.data["key"], handle);
}
//Return true if we have a stored route object for the next route
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return this.storedRouteHandles.has(route.data["key"]);
}
//If we returned true in shouldAttach(), now return the actual route data for restoration
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return this.storedRouteHandles.get(route.data["key"]);
}
//Reuse the route if we're going to and from the same route
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
}
마지막으로 기능 모듈의 라우팅 파일에서 키를 정의하십시오.
{ path: '', component: CompanyComponent, children: [
{path: '', component: CompanyListComponent, data: {key: "company"}},
{path: ':companyID', component: CompanyDetailComponent},
]}
답변
더 유효하고 완전하며 재사용 가능한 또 다른 구현입니다. 이것은 @ Uğur Dinç로 지연로드 된 모듈을 지원하고 @Davor 경로 데이터 플래그를 통합합니다. 가장 좋은 점은 페이지 절대 경로를 기반으로 (거의) 고유 식별자를 자동으로 생성하는 것입니다. 이렇게하면 모든 페이지에서 직접 정의 할 필요가 없습니다.
설정을 캐시 할 페이지를 표시하십시오 reuseRoute: true
. shouldDetach
방법에 사용됩니다 .
{
path: '',
component: MyPageComponent,
data: { reuseRoute: true },
}
이것은 쿼리 매개 변수를 비교하지 않고 가장 간단한 전략 구현입니다.
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, UrlSegment } from '@angular/router'
export class CustomReuseStrategy implements RouteReuseStrategy {
storedHandles: { [key: string]: DetachedRouteHandle } = {};
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute || false;
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const id = this.createIdentifier(route);
if (route.data.reuseRoute) {
this.storedHandles[id] = handle;
}
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const id = this.createIdentifier(route);
const handle = this.storedHandles[id];
const canAttach = !!route.routeConfig && !!handle;
return canAttach;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const id = this.createIdentifier(route);
if (!route.routeConfig || !this.storedHandles[id]) return null;
return this.storedHandles[id];
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
private createIdentifier(route: ActivatedRouteSnapshot) {
// Build the complete path from the root to the input route
const segments: UrlSegment[][] = route.pathFromRoot.map(r => r.url);
const subpaths = ([] as UrlSegment[]).concat(...segments).map(segment => segment.path);
// Result: ${route_depth}-${path}
return segments.length + '-' + subpaths.join('/');
}
}
이것은 또한 쿼리 매개 변수를 비교합니다. compareObjects
@Corbfon 버전에 비해 약간 개선되었습니다. 기본 및 비교 개체의 속성을 통해 반복합니다. lodash isEqual
메서드 와 같은 외부적이고 더 안정적인 구현을 사용할 수 있습니다 .
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, UrlSegment } from '@angular/router'
interface RouteStorageObject {
snapshot: ActivatedRouteSnapshot;
handle: DetachedRouteHandle;
}
export class CustomReuseStrategy implements RouteReuseStrategy {
storedRoutes: { [key: string]: RouteStorageObject } = {};
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute || false;
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const id = this.createIdentifier(route);
if (route.data.reuseRoute && id.length > 0) {
this.storedRoutes[id] = { handle, snapshot: route };
}
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const id = this.createIdentifier(route);
const storedObject = this.storedRoutes[id];
const canAttach = !!route.routeConfig && !!storedObject;
if (!canAttach) return false;
const paramsMatch = this.compareObjects(route.params, storedObject.snapshot.params);
const queryParamsMatch = this.compareObjects(route.queryParams, storedObject.snapshot.queryParams);
console.log('deciding to attach...', route, 'does it match?');
console.log('param comparison:', paramsMatch);
console.log('query param comparison', queryParamsMatch);
console.log(storedObject.snapshot, 'return: ', paramsMatch && queryParamsMatch);
return paramsMatch && queryParamsMatch;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const id = this.createIdentifier(route);
if (!route.routeConfig || !this.storedRoutes[id]) return null;
return this.storedRoutes[id].handle;
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
private createIdentifier(route: ActivatedRouteSnapshot) {
// Build the complete path from the root to the input route
const segments: UrlSegment[][] = route.pathFromRoot.map(r => r.url);
const subpaths = ([] as UrlSegment[]).concat(...segments).map(segment => segment.path);
// Result: ${route_depth}-${path}
return segments.length + '-' + subpaths.join('/');
}
private compareObjects(base: any, compare: any): boolean {
// loop through all properties
for (const baseProperty in { ...base, ...compare }) {
// 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:
// tslint:disable-next-line triple-equals
if (base[baseProperty] != compare[baseProperty]) {
return false;
}
}
} else {
return false;
}
}
// returns true only after false HAS NOT BEEN returned through all loops
return true;
}
}
고유 키를 생성하는 가장 좋은 방법이 있으면 내 대답에 주석을 달면 코드를 업데이트하겠습니다.
해결책을 공유해 주신 모든 분들께 감사드립니다.
답변
언급 된 모든 솔루션은 우리의 경우에는 불충분했습니다. 다음과 같은 소규모 비즈니스 앱이 있습니다.
- 소개 페이지
- 로그인 페이지
- 앱 (로그인 후)
우리의 요구 사항 :
- 지연로드 된 모듈
- 다단계 경로
- 앱 섹션의 메모리에 모든 라우터 / 구성 요소 상태 저장
- 특정 경로에서 기본 각도 재사용 전략을 사용하는 옵션
- 로그 아웃시 메모리에 저장된 모든 구성 요소 삭제
경로의 단순화 된 예 :
const routes: Routes = [{
path: '',
children: [
{
path: '',
canActivate: [CanActivate],
loadChildren: () => import('./modules/dashboard/dashboard.module').then(module => module.DashboardModule)
},
{
path: 'companies',
canActivate: [CanActivate],
loadChildren: () => import('./modules/company/company.module').then(module => module.CompanyModule)
}
]
},
{
path: 'login',
loadChildren: () => import('./modules/login/login.module').then(module => module.LoginModule),
data: {
defaultReuseStrategy: true, // Ignore our custom route strategy
resetReuseStrategy: true // Logout redirect user to login and all data are destroyed
}
}];
재사용 전략 :
export class AppReuseStrategy implements RouteReuseStrategy {
private handles: Map<string, DetachedRouteHandle> = new Map();
// Asks if a snapshot from the current routing can be used for the future routing.
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
// Asks if a snapshot for the current route already has been stored.
// Return true, if handles map contains the right snapshot and the router should re-attach this snapshot to the routing.
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
if (this.shouldResetReuseStrategy(route)) {
this.deactivateAllHandles();
return false;
}
if (this.shouldIgnoreReuseStrategy(route)) {
return false;
}
return this.handles.has(this.getKey(route));
}
// Load the snapshot from storage. It's only called, if the shouldAttach-method returned true.
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
return this.handles.get(this.getKey(route)) || null;
}
// Asks if the snapshot should be detached from the router.
// That means that the router will no longer handle this snapshot after it has been stored by calling the store-method.
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return !this.shouldIgnoreReuseStrategy(route);
}
// After the router has asked by using the shouldDetach-method and it returned true, the store-method is called (not immediately but some time later).
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {
if (!handle) {
return;
}
this.handles.set(this.getKey(route), handle);
}
private shouldResetReuseStrategy(route: ActivatedRouteSnapshot): boolean {
let snapshot: ActivatedRouteSnapshot = route;
while (snapshot.children && snapshot.children.length) {
snapshot = snapshot.children[0];
}
return snapshot.data && snapshot.data.resetReuseStrategy;
}
private shouldIgnoreReuseStrategy(route: ActivatedRouteSnapshot): boolean {
return route.data && route.data.defaultReuseStrategy;
}
private deactivateAllHandles(): void {
this.handles.forEach((handle: DetachedRouteHandle) => this.destroyComponent(handle));
this.handles.clear();
}
private destroyComponent(handle: DetachedRouteHandle): void {
const componentRef: ComponentRef<any> = handle['componentRef'];
if (componentRef) {
componentRef.destroy();
}
}
private getKey(route: ActivatedRouteSnapshot): string {
return route.pathFromRoot
.map((snapshot: ActivatedRouteSnapshot) => snapshot.routeConfig ? snapshot.routeConfig.path : '')
.filter((path: string) => path.length > 0)
.join('');
}
}
답변
다음은 일입니다! 참조 : https://www.cnblogs.com/lovesangel/p/7853364.html
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {}
private static waitDelete: string
public static deleteRouteSnapshot(name: string): void {
if (CustomReuseStrategy.handlers[name]) {
delete CustomReuseStrategy.handlers[name];
} else {
CustomReuseStrategy.waitDelete = name;
}
}
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return true;
}
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
if (CustomReuseStrategy.waitDelete && CustomReuseStrategy.waitDelete == this.getRouteUrl(route)) {
// 如果待删除是当前路由则不存储快照
CustomReuseStrategy.waitDelete = null
return;
}
CustomReuseStrategy.handlers[this.getRouteUrl(route)] = handle
}
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!CustomReuseStrategy.handlers[this.getRouteUrl(route)]
}
/** 从缓存中获取快照,若无则返回nul */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig) {
return null
}
return CustomReuseStrategy.handlers[this.getRouteUrl(route)]
}
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) === JSON.stringify(curr.params);
}
private getRouteUrl(route: ActivatedRouteSnapshot) {
return route['_routerState'].url.replace(/\//g, '_')
}
}