1、定义路由快照

  新建文件SimpleReuseStrategy.ts

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

export class SimpleReuseStrategy implements RouteReuseStrategy {
static _cacheRouters: { [key: string]: any } = {};
private static _donotWriteKey: string = '' //用来避免关掉自定义tab重新写入 /**是否允许复用路由 */
shouldDetach(route: ActivatedRouteSnapshot): boolean {
if (!route.routeConfig || route.routeConfig.loadChildren) {
return false;
}
let key = this.getPathNotParams(route);
switch (key) {
case '/master/pripowerdc0240/home': return true;
case '/master/pripowerdc0240/list': return true;
case '/master/pripowerdc0240/detail/:id': return true;
default: return false;
}
} /**当路由离开时会触发 按path作为key存储路由快照&组件当前实例对象*/
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
let key = this.getCompleteKey(route);
if (SimpleReuseStrategy._donotWriteKey != '' && SimpleReuseStrategy._donotWriteKey == this.getCompleteKey(route)) {
console.log('不存储快照' + key)
SimpleReuseStrategy._donotWriteKey = ''
return;
}
SimpleReuseStrategy._cacheRouters[key] = {
snapshot: route,
handle: handle
};
} /**是否允许还原路由 */
shouldAttach(route: ActivatedRouteSnapshot): boolean {
// 在缓存中有的都认为允许还原路由
let key = this.getCompleteKey(route);
return !!route.routeConfig && !!SimpleReuseStrategy._cacheRouters[key];
} /**从缓存中获取快照 */
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
// 从缓存中获取快照,若无则返回null
let key = this.getCompleteKey(route);
if (!route.routeConfig || !SimpleReuseStrategy._cacheRouters[key]) return null;
return SimpleReuseStrategy._cacheRouters[key].handle;
} /** 进入路由触发,判断是否同一路由 */
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
// 同一路由时复用路由
return this.getCompleteKey(future) === this.getCompleteKey(curr);
} public static clearCacheRoutersBy(key: string, donotWrite = false) {
delete SimpleReuseStrategy._cacheRouters[key];
if (donotWrite) {
//不跳转写入
SimpleReuseStrategy._donotWriteKey = key;
}
} private getCompleteKey(route: ActivatedRouteSnapshot): string {
let keys: string[] = []
route.pathFromRoot.map(v =>
v.url.map(segment => {
keys.push(segment.toString());
})
);
return '/' + keys.join('/');
} private getPathNotParams(route: ActivatedRouteSnapshot): string {
let key = '';
route.pathFromRoot.map(x => {
if (x.routeConfig?.path) {
key += '/' + x.routeConfig?.path;
}
});
return key;
} }

  在app.module.ts添加providers

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

  在需要缓存快照的子路由添加providers,如

import { NgModule } from '@angular/core';
import { Routes, RouterModule, RouteReuseStrategy } from '@angular/router';
import { HomeComponent } from './home/home.component'
import { DetailComponent } from './detail/detail.component'
import { ListComponent } from './list/list.component'
import { SimpleReuseStrategy } from 'src/app/SimpleReuseStrategy'; const routes: Routes = [
{
path: 'home',
component: HomeComponent,
data: { title: '首页' }
},
{
path: 'detail/:id',
component: DetailComponent,
data: { title: '详情' }
},
{
path: 'list',
component: ListComponent,
data: { title: '列表' }
}
]; @NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: [
{ provide: RouteReuseStrategy, useClass: SimpleReuseStrategy }
],
})
export class Pripowerdc0240RoutingModule { }

2、制作tab

  在母版页定义tab,先上截图

  

  ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { of, pipe } from 'rxjs';
import { filter, map, mergeMap } from 'rxjs/operators';
import { FoodNode, TreeService } from 'src/app/services/common/tree.service';
import { SimpleReuseStrategy } from 'src/app/SimpleReuseStrategy'; @Component({
selector: 'app-master',
templateUrl: './master.component.html',
styleUrls: ['./master.component.scss']
})
export class MasterComponent implements OnInit { show = true;
@ViewChild('asideleft') asideleft: any;
@ViewChild('asideright') asideright: any; menuList: CusRouterTabInfo[] = [];
selectedIndex = 0;
constructor(
public treeService: TreeService,
private router: Router,
private activatedRoute: ActivatedRoute
) {
this.iniMenu();
} ngOnInit(): void {
this.treeService.dataSource.data = this.TREE_DATA;
} iniMenu() {
this.router.events.pipe(
filter(event => {
return event instanceof NavigationEnd
}),
map(event => {
let path = (event as NavigationEnd).url
return { route: this.activatedRoute, path: path }
}),
map(model => {
while (model.route.firstChild) model.route = model.route.firstChild;
return model;
}),
filter(model => model.route.outlet === 'primary'),
).subscribe(model => {
model.route.data.subscribe(data => {
if(!data['title']){
return;//没有配置title的默认不添加到menuList
}
let hasIndex = this.menuList.findIndex(x => x.path == model.path);
if (hasIndex != -1) {//menuList已存在
this.selectedIndex = hasIndex;
return;
}
let menu: CusRouterTabInfo = { title: data['title'], path: model.path, isSelect: true };
this.menuList.push(menu);
this.selectedIndex = this.menuList.findIndex(x => x.path == model.path)
})
})
} showleft() {
this.asideleft.nativeElement.style.transform = 'translate(0, 0)';
this.asideright.nativeElement.style.transform = 'translate(0, 0)';
this.asideright.nativeElement.style.width = 'calc(100% - 12vw)';
this.asideright.nativeElement.style.marginleft = '12vw';
this.show = true;
}
hideleft() {
this.asideleft.nativeElement.style.transform = 'translate(-100%, 0)';
this.asideright.nativeElement.style.transform = 'translate(-12vw, 0)';
this.asideright.nativeElement.style.width = '100%';
this.asideright.nativeElement.style.marginleft = 0;
this.show = false;
} TREE_DATA: FoodNode[] = [
{
id: '0120',
name: 'UPS电源设备',
children: [
{ id: '/manager_specialist/partsearch/list', name: '80-NET系列' },
]
},
{
id: '0240',
name: '一次电源配电柜',
children: [
{ id: '/master/pripowerdc0240/home', name: 'home' },
{ id: '/master/pripowerdc0240/detail/111', name: 'detail' },
{ id: '/master/pripowerdc0240/detail/222', name: 'detail' },
{ id: '/master/pripowerdc0240/list', name: 'list' },
],
}
] deleteMenuList(path: string) {
if (this.menuList.length <= 1) { //只有一个不删
return;
}
let delIndex = this.menuList.findIndex(x => x.path == path);
this.menuList.splice(delIndex, 1);//删除
SimpleReuseStrategy.clearCacheRoutersBy(path, true);
if (delIndex == 0) { //关的是第一个
this.router.navigate([this.menuList[0].path]);
return;
}
//关的其他
this.router.navigate([this.menuList[delIndex - 1].path]);
}
gotoPath(path: string) {
console.log('gotoPath:' + path);
this.router.navigate([path]);
}
} interface CusRouterTabInfo {
title: string
path: string
isSelect: boolean
}

  html

<div class="left" #asideleft>
<div class="logobox">
<div class="logo">
<img src="/assets/images/vlogo.png">
</div>
</div> <div class="tree">
<mat-tree [dataSource]="treeService.dataSource" [treeControl]="treeService.treeControl">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding>
<button mat-icon-button disabled></button>
<span [routerLink]="node.id" routerLinkActive="active">&nbsp;&nbsp;{{node.name}}</span>
<!-- <span routerLink="/plm/productconfig/list/{{node.id}}" routerLinkActive="active">{{node.name}}</span> -->
</mat-tree-node>
<mat-tree-node *matTreeNodeDef="let node;when: treeService.hasChild" matTreeNodeToggle>
<button mat-icon-button [attr.aria-label]="'Toggle ' + node.name">
<mat-icon class="mat-icon-rtl-mirror">
{{treeService.treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
<span>{{node.name}}</span>
</mat-tree-node>
</mat-tree>
</div> </div> <div class="content" #asideright>
<div class="contenttop">
<div class="contenttopleft">
<div (click)="showleft()" *ngIf="!show">
<mat-icon>reorder</mat-icon>
</div>
<div (click)="hideleft()" *ngIf="show">
<mat-icon>reorder</mat-icon>
</div>
</div>
<div class="contenttopcenter">
<b>专家库后台管理</b>
</div>
<div class="contenttopright">
Dear:<b style="color: #fff;">admin</b>
<button mat-button style="color: #fff;margin-right: 2vw;">退出<mat-icon>logout</mat-icon></button>
</div>
</div> <div class="router">
<mat-tab-group mat-align-tabs="start" [selectedIndex]="selectedIndex" *ngIf="menuList.length!=0">
<mat-tab *ngFor="let menu of menuList" class="mattab">
<div style="width: 100%">
<ng-template mat-tab-label>
<input type="text" [value]="menu.title" readonly='true' (click)="gotoPath(menu.path)">
<mat-icon class="closeIcon" (click)="deleteMenuList(menu.path)">close</mat-icon>
</ng-template>
</div>
</mat-tab>
</mat-tab-group>
<!-- <button mat-button (click)="loadCacheRouters()">load</button> -->
</div> <div class="contentrouting">
<router-outlet></router-outlet>
</div>
</div>

  scss

.left{
float: left;
background-color: #607B8B;
height: 100vh;
width: 12vw;
transition: all 1s;
z-index: 2;
position:absolute;
.logobox{
background-color: #68838B;
border-radius: 7px;
width: 100%;
height: 4vw;
.logo{
padding: 1vh 1vw;
img{
width: 100%;
height: 100%;
}
}
}
} .content{
z-index: 1;
position:absolute;
margin-left: 12vw;
background-color: #DCDCDC;
height: 100vh;
width: 88vw;
transition: all 1s;
// transition: all 1s;
} .contenttop{
height: 6vh;
width: 100%;
line-height: 5.5vh;
background-color: #B5B5B5;
position: relative;
.contenttopleft{
float: left;
line-height: 100%;
.mat-icon{
cursor: pointer;
}
}
.contenttopcenter{
float: left;
// width: 30vw;
margin-left: 35vw;
b{
font-size: 1.3rem;
color: #DCDCDC;
}
}
.contenttopright{
float: right;
}
} .contentrouting{
height: calc(94vh - 30px);
width: 100%;
line-height: unset;
} ::ng-deep{
.mat-tree{
background:none;
mat-tree-node{
padding-left: 0 !important;
}
.mat-tree-node{
color: #DCDCDC;
// color: red;
min-height: 20px;
height: auto;
padding-left: 10px;
button{
width: 20px;
height: 30px;
line-height: 30px;
}
span{
cursor: pointer;
width: 100%;
height: auto;
user-select: none;
}
}
}
} .router{
input{
border: 0;
// background: none;
cursor: pointer;
height: 28px;
width: 100%;
}
input:focus{
outline: none;
}
.closeIcon{
margin-left: 2px;
font-size: 12px;
height: 100%;
background: red;
border-radius: 50%;
width: 12px;
height: 12px;
position: absolute;
right: 5px;
} } .active{
color: #CD950C;
} :host ::ng-deep{
.mat-tab-label{
height: 30px !important;
border-top-left-radius: 15px;
border-top-right-radius: 15px;
.mat-tab-label-content{
position: absolute;
left: 0;
}
}
.mat-tab-group{
height: 30px !important;
.mat-tab-labels{
height: 30px !important;
}
}
}

  完毕!!!

Angular 利用路由快照实现tab的更多相关文章

  1. angular利用ui-router登录检查

    angular利用ui-router登录检查 SAP都会有这个问题,session过期或者页面被刷新的情况下应该进入登录页. 监听ui-router的satte事件可以实现当state切换的时候检查登 ...

  2. 烂泥:KVM利用LVM快照快速部署虚拟机

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 上一篇文章介绍了有关KVM利用LVM快照备份和恢复虚拟机的功能,这篇文章我们来介绍,如何利用LVM快照功能为KVM快速部署虚拟机. 部署虚拟机需要以下几 ...

  3. 烂泥:LVM学习之KVM利用LVM快照备份与恢复虚拟机

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 最近一段时间一直在学习有关LVM逻辑卷方面的知识,前几篇文章介绍了有关LVM的逻辑卷的基本相关知识,包括逻辑卷及卷组的扩容与缩小.今天我们再来介绍LVM ...

  4. 利用路由修改thinkphp框架开发的后台地址

    一般我们写前台是home 后台是 admin那么我们的后台是 域名/admin 那我们要随时修改这个地址是非常麻烦的事情开始可能会想到,就是把模块名称改掉,或者分组(3.1版)这样的话不但要改配置,连 ...

  5. Angular 4 路由介绍

    Angular 4 路由 1. 创建工程 ng new router --routing 2. 创建home和product组件 ng g component home ng g component ...

  6. angular -- ng-ui-route路由及其传递参数?script标签版

    考虑到 多视图等因素,所以 angular 的路由考虑使用 ng-ui-route来做,而不使用 ng-route来做! <!DOCTYPE html> <html lang=&qu ...

  7. angular 之路由

    1.用angular-cli建一个工程自带路由怎么做? 命令:ng new  项目名 --routing 2.怎么使用路由器和路由器的一些基本使用. //html页面 <a routerLink ...

  8. angular 前端路由不生效解决方案

    angular 前端路由不生效解决方案 Intro 最近使用 Angular 为我的活动室预约项目开发一个前后端分离的客户端,在部署上遇到了一个问题,前端路由不生效,这里记录一下.本地开发正常,但是部 ...

  9. Angular配置路由以及动态路由取值传值跳转

    Angular配置路由 1.找到 app-routing.module.ts 配置路由 引入组件 import { HomeComponent } from './home/home.componen ...

  10. 理解 angular 的路由功能

    相信很多人使用angular 都是因为他路由功能而用的 深入理解ANGULARUI路由_UI-ROUTER 最近在用 ionic写个webapp 看到几个demo中路由有好几种,搞的有点晕,查下资料研 ...

随机推荐

  1. 秒懂 Golang 中的 条件变量(sync.Cond)

    本篇文章面向的读者: 已经基本掌握Go中的 协程(goroutine),通道(channel),互斥锁(sync.Mutex),读写锁(sync.RWMutex) 这些知识.如果对这些还不太懂,可以先 ...

  2. SQL注入问题、视图、触发器、事物、存储过程、函数、流程控制、索引相关概念、索引数据结构、慢查询优化、

    目录 SQL注入问题 视图 触发器 事物 存储过程 函数 流程控制 索引相关概念 索引数据结构 慢查询优化 测试装备 联合索引 全文检索 插入数据 更新数据 删除数据 主键 外键 重命名表 事物 安全 ...

  3. 微软跨平台maui开发chatgpt客户端

    image 什么是maui .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动(ios,andriod)和桌面(windows,mac)应 ...

  4. CVE-2020-1957

    漏洞名称 Apache Shiro 认证绕过漏洞 CVE-2020-1957 利用条件 Apache Shiro < 1.5.1 漏洞原理 Apache Shiro 是一款开源安全框架,提供身份 ...

  5. CVE-2016-4437

    漏洞名称 Apache shiro 1.2.4反序列化漏洞(CVE-2016-4437) 利用条件 Apache Shiro <= 1.2.4 漏洞原理 Shiro提供了记住我(Remember ...

  6. Openmp Runtime 库函数汇总(上)

    Openmp Runtime 库函数汇总(上) omp_in_parallel,如果当前线程正在并行域内部,则此函数返回true,否则返回false. #include <stdio.h> ...

  7. 解决 requests cookies 为空的坑

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/5d14f0d7.html 你好,我是测试蔡坨坨. 我们在做接口自动化测试的时候,一般会通过调用登录接口来获取cookies. ...

  8. Vue导出模板、使用前端js办法导出表格数据、导入表格前端读取表格数据、导入表格发送后端读取数据

    以下是几种用的较多的函数方法,可以参考使用. // 導出1 myExport() { // post請求文件寫法1 const url = 'http://XXXX/XXXX/XXXX/XXXX' c ...

  9. angular打包出现JavaScript堆内存不足、启动也会内存溢出解决办法\increase-memory-limit' 不是内部或外部命令,

    ## 打包出现JavaScript堆内存不足 最近打包遇到这种报错 Ineffective mark-compacts near heap limit Allocation failed - Java ...

  10. Grafana 系列文章(五):Grafana Explore 查询管理

    ️URL: https://grafana.com/docs/grafana/latest/explore/query-management/ Description: Explore 中的查询管理 ...