ルーティングを実装したAngular 2モジュールがあり、ナビゲーション時に状態を保存したいのですが。 1.検索式を使用してドキュメントを検索する2.結果の1つに移動する3. searchresultに戻る-サーバーと通信せずに
これは、RouteReuseStrategyを含めて可能です。問題は、ドキュメントを保存しないように実装するにはどうすればよいですか?
したがって、ルートパス「documents」の状態は保存され、ルートパス「documents /:id」の状態は保存されません。
受け入れられた答えに怖がらないでください。これは非常に簡単です。必要なものを簡単に答えます。私は少なくとも受け入れられた答えを読むことをお勧めします。それは非常に詳細に満ちているからです。
このソリューションは、受け入れられた答えのようなパラメータ比較を行いませんが、ルートのセットを保存するためにうまく機能します。
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;
}
}
遅延ロードされたモジュールで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},
]}
詳細 こちら 。
受け入れられた回答(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;
}
次は仕事です!参照: 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, '_')
}
}
より有効で完全かつ再利用可能な別の実装。これは、遅延ロードされたモジュールを@UğurDinçとしてサポートし、@ 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;
}
}
一意のキーを生成する最良の方法があれば、私の答えをコメントして、コードを更新します。
ソリューションを共有してくれたすべての人に感謝します。