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,如何编写测试用例,快来观摩......作为一名测试人员如果连常见的系统问题都不知道如何分析,频繁将前端人员问题指派给后端人员,后端人员问题指派给前端人员…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
Appium下载安装配置保姆教程(图文详解)
目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...
AT模式下的全局锁冲突如何解决?
一、全局锁冲突解决方案 1. 业务层重试机制(推荐方案) Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减(自动加全…...
02-性能方案设计
需求分析与测试设计 根据具体的性能测试需求,确定测试类型,以及压测的模块(web/mysql/redis/系统整体)前期要与相关人员充分沟通,初步确定压测方案及具体的性能指标QA完成性能测试设计后,需产出测试方案文档发送邮件到项目组&…...
