Angular 利用路由快照实现tab
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"> {{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的更多相关文章
- angular利用ui-router登录检查
angular利用ui-router登录检查 SAP都会有这个问题,session过期或者页面被刷新的情况下应该进入登录页. 监听ui-router的satte事件可以实现当state切换的时候检查登 ...
- 烂泥:KVM利用LVM快照快速部署虚拟机
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 上一篇文章介绍了有关KVM利用LVM快照备份和恢复虚拟机的功能,这篇文章我们来介绍,如何利用LVM快照功能为KVM快速部署虚拟机. 部署虚拟机需要以下几 ...
- 烂泥:LVM学习之KVM利用LVM快照备份与恢复虚拟机
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 最近一段时间一直在学习有关LVM逻辑卷方面的知识,前几篇文章介绍了有关LVM的逻辑卷的基本相关知识,包括逻辑卷及卷组的扩容与缩小.今天我们再来介绍LVM ...
- 利用路由修改thinkphp框架开发的后台地址
一般我们写前台是home 后台是 admin那么我们的后台是 域名/admin 那我们要随时修改这个地址是非常麻烦的事情开始可能会想到,就是把模块名称改掉,或者分组(3.1版)这样的话不但要改配置,连 ...
- Angular 4 路由介绍
Angular 4 路由 1. 创建工程 ng new router --routing 2. 创建home和product组件 ng g component home ng g component ...
- angular -- ng-ui-route路由及其传递参数?script标签版
考虑到 多视图等因素,所以 angular 的路由考虑使用 ng-ui-route来做,而不使用 ng-route来做! <!DOCTYPE html> <html lang=&qu ...
- angular 之路由
1.用angular-cli建一个工程自带路由怎么做? 命令:ng new 项目名 --routing 2.怎么使用路由器和路由器的一些基本使用. //html页面 <a routerLink ...
- angular 前端路由不生效解决方案
angular 前端路由不生效解决方案 Intro 最近使用 Angular 为我的活动室预约项目开发一个前后端分离的客户端,在部署上遇到了一个问题,前端路由不生效,这里记录一下.本地开发正常,但是部 ...
- Angular配置路由以及动态路由取值传值跳转
Angular配置路由 1.找到 app-routing.module.ts 配置路由 引入组件 import { HomeComponent } from './home/home.componen ...
- 理解 angular 的路由功能
相信很多人使用angular 都是因为他路由功能而用的 深入理解ANGULARUI路由_UI-ROUTER 最近在用 ionic写个webapp 看到几个demo中路由有好几种,搞的有点晕,查下资料研 ...
随机推荐
- redis集合 实现 队列
先说一下需求:用队列解决 流量削峰,主要应用场景:商城秒杀功能. 以下是业务流程图可以参考一下: 然后本地实现思路 截图下单页面 每次购买数量会减少1,设置了1000个库存,用户id 是随机生成的. ...
- 使用WPF或AspNetCore创建简易版ChatGPT客户端,让ChatGPT成为你的私人助理
前言:前一天写的一个ChatGPT服务端,貌似大家用起来还不是那么方便,所以我顺便用WPF和AspNetCore的webapi程序做个客户端吧,通过客户端来快速访问chatgpt模型生成对话. 1 ...
- day11-功能实现10
家居网购项目实现010 以下皆为部分代码,详见 https://github.com/liyuelian/furniture_mall.git 24.bugFix-添加购物车按钮动态处理 24.1需求 ...
- 字符编码:Unicode & UTF-16 & UTF-8
ASCII码 使用一个字节(8位),对128个字符进行编码: 最高位始终为0: 码数范围为0000_0000(0x00)到0111_1111(0x7F): Unicode 开始的编码设计 使用两个字节 ...
- [Leetcode]设计链表
题目 设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下一个节点的指针/引用.如果要使用双向链表,则还需要一 ...
- 无旋树堆(FHQ-Treap)学习笔记
简介 无旋树堆(一般统称 \(\text{FHQ-Treap}\)),是一种平衡树.可以用很少的代码达到很优秀的复杂度. 前置知识: 二叉搜索树 \(\text{BST}\) \(\text{Trea ...
- 如何在 Nuxt 3 中使用 wavesurfer.js
安装 wavesurfer.js 在项目中安装 wavesurfer.js npm install --save wavesurfer.js 常规方式引入 如果你的根目录中没有 components ...
- 在GCP上创建GCE的三种方式(Console,gcloud,Terraform)
1 简介 如果要选择GCP为云平台,则经常需要创建GCE(Google Compute Engine),有以下几种方式: (1) 在浏览器创建 (2) 命令 gcloud (3) Terraform ...
- C++Day09 深拷贝、写时复制(cow)、短字符串优化
一.std::string 的底层实现 1.深拷贝 1 class String{ 2 public: 3 String(const String &rhs):m_pstr(new char[ ...
- angular基础之单向绑定,双向绑定以及数据绑定失效的问题
单向绑定 事件绑定: <input (keyup)="inputChange($event)" /> 属性绑定: <input [value]="inp ...