Angular 路由复用策略

1. 前言

用 Angular 路由实现的 Tab 切换,当在不同 Tab 之间切换时,希望保留 Tab 中的状态,这时就需要用到路由复用策略 `RouteReuseStrategy`。用 上一篇 中的例子来继续说明路由复用策略:`Sub1` Tab 下有一个输入框,随便输入一些内容,当从 `Sub2` Tab 切换到 `Sub1` Tab 中时,要保留 `Sub1` Tab 中之前输入的内容。这就是本文要实现的一个效果。

Angular 路由复用策略_第1张图片

2. 原理

简单来说,就是当离开当前路由的时候,将当前路由的快照存起来,当再次进入到该路由时,再取之前存的快照来恢复当前路由的一个状态。

3. 代码

1. 实现 `RouteReuseStrategy`。

网上很多大神已经实现了,这里我就直接拿过来用了。

// SimpleReuseStrategy.ts

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

export class SimpleReuseStrategy implements RouteReuseStrategy {

public static handlers: { [key: string]: DetachedRouteHandle } = {}

private static waitDelete: string

/** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断 */
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
console.debug('===shouldDetach-route', route);
return true;
}

/** 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象 */
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
console.debug('===store-route', route, 'store-handle', handle);
SimpleReuseStrategy.handlers[this.getRouteUrl(route)] = handle
}

/** 若 path 在缓存中有的都认为允许还原路由 */
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
console.debug('===shouldAttach-route', route);
return !!SimpleReuseStrategy.handlers[this.getRouteUrl(route)]
}

/** 从缓存中获取快照,若无则返回null */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
console.debug('===retrieve-route', route);
if (!route.routeConfig) {
return null
}

return SimpleReuseStrategy.handlers[this.getRouteUrl(route)]
}

/** 进入路由触发,判断是否同一路由 */
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
console.debug('===shouldReuseRoute-future', future, 'shouldReuseRoute-cur', curr);
return future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) == JSON.stringify(curr.params);
}

private getRouteUrl(route: ActivatedRouteSnapshot) {
var path = route['_routerState'].url.replace(/\//g, '_');
console.debug('---getRouteUrl-path', path);
return path;
}

public static deleteRouteSnapshot(name: string): void {
if (SimpleReuseStrategy.handlers[name]) {
delete SimpleReuseStrategy.handlers[name];
} else {
SimpleReuseStrategy.waitDelete = name;
}
}
}


2. 将该策略注入到 AppModule 中。

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { SimpleReuseStrategy } from './route/SimpleReuseStrategy';
import { RouteReuseStrategy } from '@angular/router';
import { LazyHomeComponent } from './lazy-home/lazy-home.component';

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [{ provide: RouteReuseStrategy, useClass: SimpleReuseStrategy}],
bootstrap: [AppComponent]
})
export class AppModule { }


3. 在 app.component.ts 中添加路由事件。

import { Component } from '@angular/core';
import { SimpleReuseStrategy } from './route/SimpleReuseStrategy';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [SimpleReuseStrategy]
})
export class AppComponent {
title = 'app';

menuList: Array<{ module: string }>=[];

constructor(private router: Router,
private activatedRoute: ActivatedRoute) {
//路由事件
this.router.events.filter(event => event instanceof NavigationEnd)
.map(() => this.activatedRoute)
.map(route => {
while (route.firstChild) route = route.firstChild;
return route;
})
.filter(route => route.outlet === 'primary')
.mergeMap(route => route.data)
.subscribe((event) => {
var menu = { module: event["module"]};
this.menuList.push(menu);
});
}
}


4. 路由中 data 的定义。

为各个路由添加 data 的定义。

const routes: Routes = [
{
path: '',
component: LazyHomeComponent,
children:[
{
path:'home-sub1',
loadChildren:'./lazy-home-sub1.module#LazyHomeSub1Module',
data:{ module:'LazyHomeSub1Module'}
},
{
path:'home-sub2',
loadChildren:'./lazy-home-sub2.module#LazyHomeSub2Module',
data:{ module:'LazyHomeSub2Module'}
}
]
}
];

4. 问题

如果遇到 `Error: Cannot reattach ActivatedRouteSnapshot created from a different route` 这个问题,可以参考 :

https://stackoverflow.com/questions/41584664/error-cannot-reattach-activatedroutesnapshot-created-from-a-different-route

5. 参考网址

http://www.cnblogs.com/lslgg/p/7700888.html 

https://zhuanlan.zhihu.com/p/29823560

http://ng-alain.com/components/reuse-tab 

https://angular.io/api/router/RouteReuseStrategy

https://www.cnblogs.com/lovesangel/p/7853364.html

https://zhuanlan.zhihu.com/p/29823560 

你可能感兴趣的:(前端)