使用场景

打开菜单页面的时候,出现对应页面的页签。切换页签,原来的页面信息状态保留,关闭页签则保留的信息删除。使用路由复用策略,保存路由快照。
实现效果如图所示
实现过程

  概述:

1、在app.module.ts注册

 providers: [
{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy }
],

2、新建RouteReuseStrategy

新建一个CustomReuseStrategy.ts

贴上代码(解决了位于三级菜单的页面与位于一级菜单或者二级菜单无法跳转的问题之后的代码)

import {ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy} from '@angular/router';
import {Injectable} from '@angular/core'; interface IRouteConfigData {
reuse: boolean;
} interface ICachedRoute {
handle: DetachedRouteHandle;
data: IRouteConfigData;
} @Injectable()
export class AppReuseStrategy implements RouteReuseStrategy {
private static routeCache = new Map<string, ICachedRoute>();
private static waitDelete: string; // 当前页未进行存储时需要删除
private static currentDelete: string; // 当前页存储过时需要删除 /** 进入路由触发,判断是否是同一路由 */
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
} /** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断,这里判断是否有data数据判断是否复用 */
shouldDetach(route: ActivatedRouteSnapshot): boolean {
if (!route.data.keep) {
return false;
}
if (!route.routeConfig || route.routeConfig.loadChildren) {
return false;
}
return true;
} /** 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象 */
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const url = this.getFullRouteUrl(route);
const data = this.getRouteData(route);
if (AppReuseStrategy.waitDelete && AppReuseStrategy.waitDelete === url) {
// 如果待删除是当前路由,且未存储过则不存储快照
AppReuseStrategy.waitDelete = null;
return null;
} else {
// 如果待删除是当前路由,且存储过则不存储快照
if (AppReuseStrategy.currentDelete && AppReuseStrategy.currentDelete === url) {
AppReuseStrategy.currentDelete = null;
return null;
} else {
AppReuseStrategy.routeCache.set(url, {handle, data});
this.addRedirectsRecursively(route);
}
}
} /** 若 path 在缓存中有的都认为允许还原路由 */
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const url = this.getFullRouteUrl(route);
return AppReuseStrategy.routeCache.has(url);
} /** 从缓存中获取快照,若无则返回nul */
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const url = this.getFullRouteUrl(route);
const data = this.getRouteData(route);
return data && AppReuseStrategy.routeCache.has(url)
? AppReuseStrategy.routeCache.get(url).handle
: null;
} private addRedirectsRecursively(route: ActivatedRouteSnapshot): void {
const config = route.routeConfig;
if (config) {
if (!config.loadChildren) {
const routeFirstChild = route.firstChild;
const routeFirstChildUrl = routeFirstChild ? this.getRouteUrlPaths(routeFirstChild).join('/') : '';
const childConfigs = config.children;
if (childConfigs) {
const childConfigWithRedirect = childConfigs.find(c => c.path === '' && !!c.redirectTo);
if (childConfigWithRedirect) {
childConfigWithRedirect.redirectTo = routeFirstChildUrl;
}
}
}
route.children.forEach(childRoute => this.addRedirectsRecursively(childRoute));
}
} private getFullRouteUrl(route: ActivatedRouteSnapshot): string {
return this.getFullRouteUrlPaths(route).filter(Boolean).join('/').replace('/', '_');
} private getFullRouteUrlPaths(route: ActivatedRouteSnapshot): string[] {
const paths = this.getRouteUrlPaths(route);
return route.parent ? [...this.getFullRouteUrlPaths(route.parent), ...paths] : paths;
} private getRouteUrlPaths(route: ActivatedRouteSnapshot): string[] {
return route.url.map(urlSegment => urlSegment.path);
} private getRouteData(route: ActivatedRouteSnapshot): IRouteConfigData {
return route.routeConfig && route.routeConfig.data as IRouteConfigData;
} /** 用于删除路由快照*/
public static deleteRouteSnapshot(url: string): void {
let arr: any = []
arr = url.split('?')
url = arr[0]
if (url[0] === '/') {
url = url.substring(1);
}
url = url.replace('/', '_');
if (AppReuseStrategy.routeCache.has(url)) {
AppReuseStrategy.routeCache.delete(url);
AppReuseStrategy.currentDelete = url;
} else {
AppReuseStrategy.waitDelete = url;
}
}
}
附上相关API文档:
[RouteReuseStrategy](https://www.angular.cn/api/router/RouteReuseStrategy)

3、关闭页签的时候,同时删除快照

解决办法:在实现页签的页面,关闭按钮那里,删除页签数组之后,加入以下代码:
    // link就是当前关闭页面的路由
setTimeout(()=>{
AppReuseStrategy.deleteRouteSnapshot(link);
}, 0)

4、其他

值得注意的是,如果页面中有定时器,离开页面的时候,需要暂时删除该定时器。
但保存路由快照之后,离开该页面的时候,不经过ngOnDestroy。
解决办法:
this.router.events.filter(event => event instanceof NavigationEnd)
.subscribe((event) => {
// 路由data的标题
clearInterval(this.interval)
});

用于实现tab页签切换页面的angular路由复用策略的更多相关文章

  1. 使用原生js与jQuery分别实现一个简单的tab页签

    tab页签通常适用于空间有限而内容较多同时兼顾页面美观度不给用户一种信息过量视觉疲劳的情形.使用面非常广,下面我们用两种方法简单实现之. 首先,构建页面元素.页签的可点击部分我们通常用列表来承载,包括 ...

  2. Tab页签切换

    js之tab页签切换效果       现在web网站,很多地都需要用到tab页签. 示例:         $(document).ready(function(){               va ...

  3. tab页签

    <div class="fl" id="newsBox"> <div class="tab1 grayBar"> & ...

  4. bootStrap中Tab页签切换

    关于$().tab()一般用来实现标签页和胶囊链接内容片段的切换,或是相关内容的页面导航: <ul class="nav nav-tabs" id="myTab&q ...

  5. ASP.NET MVC搭建项目后台UI框架—4、tab多页签支持

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  6. bootstrap 切换页签失效的解决方法

    概述 bootstrap开发标签页时,标签页显示正常,但点击时候对应内容区域没有变化. 具体症状与解决方案 1.标签页UI出现,但点击无反应,标签页UI并未随点击进行切换 先检查bootstrap.c ...

  7. android123 zhihuibeijing 新闻中心-新闻 页签 ViewPagerIndicator实现

    ## ViewPagerIndicator ## 使用导入ViewPagerIndicator库的方式相当于可以改源码,打包编译Eclips可以自动完成. ViewPager指针项目,在使用ViewP ...

  8. 网页打印A4纸-----表格在跨页时自动换页打印的实现 (转)

    在最近所做的一个项目中,需要通过网页来打印不少的表单,但是又不想每个打印页签各占用一个页面,这样就需要生存很多不同的冗余页面,为了减少冗余,所有的表单通过jquery的页签tab来实现的. 一 :基本 ...

  9. 值得分享的Bootstrap Ace模板实现菜单和Tab页效果(转)

    Ace模板地址:http://code.google.com/p/ace-engine/wiki/AceTemplate(有时会打不开) Ace英文官网:http://wrapbootstrap.co ...

随机推荐

  1. vue在钩子中引用方法不成功

    在组建创建成功后调用methods里的方法fn1,失败,提示not a function: created(){ getData(){} } solution: created(){ this.get ...

  2. protus中出现invalid internal memory size ==NULL

    点击8086芯片,更改internal memory size的大小为0x10000

  3. 第一篇:百度AI注册使用

    百度AI (https://ai.baidu.com/)点击右上角<控制台>进行登录 内容审核: 操作文档:

  4. GreenPlum-数据存储目录迁移及常用操作

    一.环境介绍 Greenplum5 3节点集群,Centos7.2虚拟机, 二.需求 因为/home目录磁盘空间已满,需要将Greenplum的数据存储目录转移到新的分区/opt目录下,虚拟机磁盘管理 ...

  5. unity-消息的注册,监听,回调

    最近在空闲时间准备做个小游戏,先把一些基本框架搭建好,本次记录的是消息的注册,监听和回调等 其实这些就是基于C#的委托(delegate) 第一步:定义一些委托 namespace Common.Me ...

  6. 抛开 Spring ,你知道 MyBatis 加载 Mapper 的底层原理吗?

    原文链接:抛开 Spring ,你知道 MyBatis 加载 Mapper 的底层原理吗? 大家都知道,利用 Spring 整合 MyBatis,我们可以直接利用 @MapperScan 注解或者 @ ...

  7. Life In Changsha College - SQA计划和系统测试规程

    一. SQA计划 (1)     对软件进行测试,保证软件不出问题: (2)     项目需要符合IEEE.ISO等软件工程标准 (3)     软件拥有基本的流程图.类图.数据流图等 (4)    ...

  8. [SD心灵鸡汤]001.每月一则 - 2015.05

    1.既然我的父母不能带给我荣耀,那我要做的就只是带给我的子女荣耀,而不是无聊的嫉妒眼红别人. 2.就人生游戏讲,男人是女人的玩物,女人是魔鬼的玩物.就爱情而言,女人是专业的,男人是业余的. 3.快乐使 ...

  9. 【docker系列2】docker 的前世今生

    Docker 入门,共 3 篇,将带大家进入 Docker 的世界.首先了解 Docker 的发展历程, 然后快速掌握 Docker 的基本使用: Docker 版本及内核兼容性选择是这部分的重点内容 ...

  10. PAT1067 试密码 (20分)——测试点4分析 一个易错点

    1067 试密码 (20分)   当你试图登录某个系统却忘了密码时,系统一般只会允许你尝试有限多次,当超出允许次数时,账号就会被锁死.本题就请你实现这个小功能. 输入格式: 输入在第一行给出一个密码( ...