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中路由有好几种,搞的有点晕,查下资料研 ...
随机推荐
- 保存sklearn中模型的两种方法(pickle、joblib)
保存sklearn中模型的两种方法(pickle.joblib) from sklearn import svm from sklearn import datasets clf = svm.SVC( ...
- Day36:List详解
List 1.1 概述 List为Collection的子接口,代表的一组任意对象,有序,有下标.元素可以重复. 1.2 方法 方法名 说明 void add(int index,Object o) ...
- Linux NTP工具的基本使用
NTP 时间同步 NTP(Network Time Protocol)协议,网络时间协议.利用ntp协议可以实现网络中的计算机时间同步. 实现NTP协议的工具: ntpdate:只能同步一次时间 nt ...
- Salesforce LWC学习(四十) datatable的dynamic action的小坑浅谈
本篇参考:https://developer.salesforce.com/docs/component-library/bundle/lightning-datatable/documentatio ...
- nuxt.js安装使用
首先要学会看文档,https://www.nuxtjs.cn/guide/configuration 一.创建项目,并运行 终端运行 npx create-nuxt-app <项目名> ( ...
- Spring IoC的一些知识点
在日常开发中,接触得比较多的算是Spring生态了,Spring Ioc是Spring Framework重要的组成部分,下面整理了一些Spring Ioc的知识点. 1. 什么是IoC IoC(In ...
- k8s本地联调工具kt-connect
1.Kt Connect简介 KT Connect ( Kubernetes Developer Tool ) 是轻量级的面向 Kubernetes 用户的开发测试环境治理辅助工具.其核心是通过建立本 ...
- ArcGIS工具 - 统计工具数量
ESRI作为GIS行业中的龙头,代表产品ArcGIS也在不断地优化和升级,从10.0开始已发布了8个版本,其工具箱(ToolBox)是它一个特色,每个版本的工具箱数量是不相同的,为源地理来教您如何统计 ...
- 【力扣】787. K 站中转内最便宜的航班加权——有向图最短路径
前言 我感觉这题比较有代表性,所以记录一下,这题是加权有向图中求最短路径的问题. 题目 787. K 站中转内最便宜的航班 动态规划 假设有一条路径是[src, i, ..., j, dst],解法一 ...
- flutter 2.X报错 Bad state: Insecure HTTP is not allowed by platform:
flutter2.x开发遇到的问题 Bad state: Insecure HTTP is not allowed by platform: 翻译过来就是:错误状态:平台不允许不安全的HTTP: 产生 ...