react umi/max 页签(react-activation)
思路:通过react-activation实现页面缓存,通过umi-plugin-keep-alive将react-activation注入umi框架,封装页签组件最后通过路由的wrappers属性引入页面。
浏览本博客之前先看一下我的博客实现的功能是否满足需求,实现功能:
- 页面缓存
- 关闭当前页
- 阻止事件传播
- 鼠标右键>关闭当前
- 鼠标右键>关闭其他
- 鼠标右键>关闭左侧
- 鼠标右键>关闭右侧
- 鼠标右键>全部关闭(默认跳转到首页)
- 鼠标右键>重新加载(刷新缓存页面)
1.下载依赖
pnpm install react-activation@0.12.4
pnpm install umi-plugin-keep-alive@0.0.1-beta.35
2.修改.umirc.ts文件配置
import { defineConfig } from '@umijs/max';export default defineConfig({plugins: ['umi-plugin-keep-alive'],...
});
3.封装组件
src目录下创建layouts文件夹,创建BaseLayout.tsx文件和BaseTabs.tsx、index.less文件
// BaseLayout.tsximport { KeepAlive, Outlet, useRouteProps } from '@umijs/max';
import React from 'react';
import BaseTabs from './BaseTabs';export default (): React.ReactElement => {const { originPath, name } = useRouteProps();return (<><BaseTabs /><KeepAlive id={originPath} name={originPath} tabName={name}><Outlet /></KeepAlive></>);
};
// BaseTabs/index.tsximport { history, useAliveController, useLocation } from '@umijs/max';
import { Dropdown, Tabs } from 'antd';
import React, { useState } from 'react';
import './index.less';export default (): React.ReactElement => {const { pathname } = useLocation();// 获取缓存列表const { getCachingNodes, dropScope, clear, refreshScope } =useAliveController();const cachingNodes = getCachingNodes();const [open, setOpen] = useState<{ path: string; open: boolean }>({path: '',open: false,});// 阻止右键事件冒泡const onRightClick = (e: React.MouseEvent<HTMLDivElement, MouseEvent>,name: string,) => open.open && open.path === name && e.stopPropagation();// 点击tab,跳转页面const clickTab = (path: string) => {history.push(path);};// 关闭tab,销毁缓存const editTab = (path: any) => {dropScope(path);// 关闭当前页面,需跳转到其他页签if (path === pathname) {const index = cachingNodes.findIndex((item) => item.name === path);if (index > 0) {history.push(cachingNodes[index - 1].name as string);} else {history.push(cachingNodes[1].name as string);}}};// 关闭当前页const onCurrent = (e: any) => {let targetKey = JSON.parse(e?.key).name;dropScope(targetKey);// 关闭当前页面,需跳转到其他页签if (targetKey === pathname) {const index = cachingNodes.findIndex((item) => item.name === targetKey);if (index > 0) {history.push(cachingNodes[index - 1].name as string);} else {history.push(cachingNodes[1].name as string);}}};// 关闭其他const onOther = (e: any) => {let targetKey = JSON.parse(e?.key).name;history.push(targetKey);clear();};//关闭左侧const onLeft = (e: any) => {let targetKey = JSON.parse(e?.key).name;const lastIndex = cachingNodes.findIndex((item) => item.name === pathname);const currIndex = cachingNodes.findIndex((item) => item.name === targetKey);if (currIndex > lastIndex) history.push(targetKey);cachingNodes.forEach((item, index) => {if (index < currIndex) {dropScope(item?.name || '');}});};// 关闭右侧const onRight = (e: any) => {let targetKey = JSON.parse(e?.key).name;const lastIndex = cachingNodes.findIndex((item) => item.name === pathname);const currIndex = cachingNodes.findIndex((item) => item.name === targetKey);if (currIndex < lastIndex) history.push(targetKey);cachingNodes.forEach((item, index) => {if (index > currIndex) {dropScope(item?.name || '');}});};// 关闭全部const onAll = () => {history.push('/home');clear();};// 重新加载const onRefresh = (e: any) => {let targetKey = JSON.parse(e?.key).name;refreshScope(targetKey);};const labelDropdown = (name: string, label: string) => {const lastIndex = cachingNodes.findIndex((item) => item.name === name);return (<div onClick={(e) => onRightClick(e, name)}><Dropdowntrigger={['contextMenu']}onOpenChange={(e) => setOpen({ path: name, open: e })}menu={{items: [{label: '关闭当前',key: JSON.stringify({ name, key: 'current' }),disabled: cachingNodes.length <= 1,onClick: onCurrent,},{label: '关闭其他',key: JSON.stringify({ name, key: 'other' }),disabled: cachingNodes.length <= 1,onClick: onOther,},{label: '关闭左侧',key: JSON.stringify({ name, key: 'left' }),disabled: lastIndex === 0,onClick: onLeft,},{label: '关闭右侧',key: JSON.stringify({ name, key: 'right' }),disabled: lastIndex === cachingNodes.length - 1,onClick: onRight,},{label: '全部关闭',key: JSON.stringify({ name, key: 'all' }),onClick: onAll,disabled: cachingNodes.length <= 1,},{label: '重新加载',key: JSON.stringify({ name, key: 'refresh' }),onClick: onRefresh,},],}}><div className={cachingNodes.length > 1 ? 'dropdown-label' : ''}>{label}</div></Dropdown></div>);};const tabItems = cachingNodes.map((item: any) => ({label: labelDropdown(item.name, item.tabName),key: item.name,closable: cachingNodes.length > 1,}));return (<TabshideAddsize='middle'type="editable-card"className="base-tabs"activeKey={pathname}onTabClick={clickTab}onEdit={editTab}items={tabItems}/>);
};
// index.less.base-tabs {.ant-dropdown-trigger {padding: 5px 10px;height: 100%;}.dropdown-label {padding: 5px 6px 5px 10px;height: 100%;}.ant-tabs-tab {padding: 0 !important;}.ant-tabs-tab-remove {margin-left: 0 !important;margin-right: 2px !important;padding-left: 0px !important;}
}
4.修改路由
routes: [{name: '首页',path: '/home',component: './Home',},{name: '示例',path: '/example',routes: [{name: '权限演示',path: '/example/access',component: './Access',wrappers: ['@/layouts/BaseLayout'],},{name: ' CRUD 示例',path: '/example/table',component: './Table',wrappers: ['@/layouts/BaseLayout'],},],},],
5.效果
相关文章:
react umi/max 页签(react-activation)
思路:通过react-activation实现页面缓存,通过umi-plugin-keep-alive将react-activation注入umi框架,封装页签组件最后通过路由的wrappers属性引入页面。 浏览本博客之前先看一下我的博客实现的功能是否满足需求,实现功能…...
计算机网络编程
一、计算机网络(概述、简介) 说起网络,相信大家都不陌生,把分散在不同地点的计算机设备,通过传输介质、通信设施和网络通信协议,实现资源共享和信息传输的系统,我们称之为:计算机网…...
【计算机网络实训】期末考题-路由重分发+三层交换机VLAN间路由
路由重分发三层交换机VLAN间路由 实验目的实验内容及步骤仿真配置环境搭建要求:实验步骤配置Switch0配置Switch1配置交换机Multilayer Switch 0路由器Router0上的配置路由器Router1的配置 测试PC0 自动获取地址成功,PC0 可 ping 通 switch0,网…...
git 常规操作及设置
git 常规操作及设置 Git是一个分布式版本控制系统,可以用来跟踪文件的修改历史并与其他人进行协作开发。下面是一些常见的Git操作及设置: 初始化仓库:使用命令git init在当前目录创建一个新的Git仓库。 克隆仓库:使用命令git clo…...
element中表格组件的row-class-name和class-name属性的使用以及无效处理
1.这两个属性的使用,row-class-name用在el-table标签上,class-name用在el-table-column标签上。两个属性即可绑定类名也可绑定函数 <!-- 这里是绑定函数,也可以绑定类名 --> <el-table :data"tableData" selection-chang…...
【AI理论知识】EM算法
基本定义 期望最大化算法(Expectation-Maximization,EM算法)是一种用于估计包含潜在变量的概率模型参数的迭代优化算法。EM算法的主要目标是在存在未观测数据或缺失数据的情况下,通过迭代地进行期望步骤(E步ÿ…...
03 OSPF
参考文章 1 初步认识OSPF的大致内容(第三课)-CSDN博客 2...
node.js(express.js)+mysql实现注册功能
文章目录 实现步骤一、获取客户端提交到服务器的用户信息,对表单中的数据,进行合法性的效验 代码如下:二、检测用户名是否被占用三、对密码进行加密四、插入新用户(完整代码)总结 实现步骤 一、获取客户端提交到服务器的用户信息…...
AI绘画Stable Diffusion进阶使用
本文讲解,模型底模,VAE美化模型,Lora模型,hypernetwork。 文本Stable Diffusion 简称sd 欢迎关注 使用模型 C站:https://civitai.com/ huggingface:https://huggingface.co/models?pipeline_tagtext-to-…...
C 练习实例33 - 质数(素数)判断
题目:判断一个数字是否为质数。 程序分析:质数(prime number)又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除。 这题做过很多遍了,懂得都懂。 代码…...
docker环境下mongo副本集的部署及异常修复
最近更换了办公地点。部署在本地docker环境里的mongo数据库不能使用了。原因是本地的ip地址变更。以前的mongo副本集的配置需要更新。处理完后,索性重新记录一下mongo副本集在docker中的部署流程。 mongo的事务及副本集 我们先了解一下什么是事务,事务…...
【Java】Maven的安装与配置
初识Maven Maven是专门用于管理和构建Java项目的工具,它的主要功能有: 提供了一套标准化的项目结构 提供了一套标准化的构建流程(编译,测试,打包,发布……) 提供了一套依赖管理机制 标准化的…...
向量和向量如何相乘?
向量与向量相乘主要有两种方式:点积(内积)和叉积(外积)。这两种运算的结果和应用是不同的。 点积(内积): 点积是两个向量的对应元素相乘后再求和的结果,通常用于计算两个…...
计算机组成原理 指令流水线
文章目录 指令流水线指令流水线的概念流水线性能分析流水线的吞吐率流水线的加速比流水线的效率 影响流水线的因素结构相关 (资源冲突)数据相关 (数据冲突)控制相关 (控制冲突) 流水线分类超量流水线 指令流水线 #mermaid-svg-sWaRASMFAvh8sLJk {font-family:"trebuchet m…...
macOS - md5 | md5sum
文章目录 简单使用介绍文档Linux - md5summacOS - md5 大文件传输是否完整,你可以使用 md5 进行校验 linux 上使用 md5sum 命令,在macOS 上 md5 命令是和 md5sum 等效的 简单使用介绍 参考:https://blog.csdn.net/cnds123321/article/detail…...
Tomcat快速入门
1.Tomcat介绍 Apache Tomcat 是由 Apache Software Foundation(ASF)开发的一个开源 Java WEB 应用服务器,如apache处理静态HTML能力突出不同,tomcat处理动态HTML能力相当强大,因此一般项目都是部署apachetomcat&#…...
如何结合antd design pro 5 结合express 上传多个文件
在Ant Design Pro 5(基于React)的前端界面结合Express后端实现上传整个文件夹的文件,实际上是在前端进行多文件选择,并通过POST请求将文件列表发送到后端,然后由后端处理上传。由于浏览器API限制,直接上传整…...
Django随笔
关于Django的admin 1. 在url中把 from django.contrib import admin 重新解开 把path(admin/,admin.site.urls), 解开 2. 注册app,在配置文件中写 django.contrib.admin, 3.输入命令进行数据库迁移 Django国际化 配置文件中(改成中文) LA…...
线程和进程的区别(从JVM角度出发)
进程与线程的区别 线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元;而把传统的进程称为重型进程(Heavy—Weight Process),它相当于只有一个线程的任务。在引入了线程的操作系统中,通常一个进…...
手把手教你如何快速定位bug,如何编写测试用例,快来观摩......
手把手教你如何快速定位bug,如何编写测试用例,快来观摩......手把手教你如何快速定位bug,如何编写测试用例,快来观摩......作为一名测试人员如果连常见的系统问题都不知道如何分析,频繁将前端人员问题指派给后端人员,后端人员问题指派给前端人员…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践
在电商行业蓬勃发展的当下,多平台运营已成为众多商家的必然选择。然而,不同电商平台在商品数据接口方面存在差异,导致商家在跨平台运营时面临诸多挑战,如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...
