1 安装组件:
安装 yarn add umi-plugin-keep-alive
2 创建模板:/src/services/types/menu.ts
export interface menuTabProps {
tab: string;
pathname?: string;
key: string;
closable?: boolean;
}
export interface menuItemProps {
name: string;
path?: string;
children?: menuItemProps[];
}
3 创建模板:/src/utils/base.ts
import type { menuItemProps } from '@/services/types/menu';
/**
* 处理菜单为一级数组
* menus: 菜单数组
*/
export const handleMenusToFlat = (menus: menuItemProps) => {
const flatMenus: any[] = [];
const handle = (arr: any) => {
arr.forEach((item: menuItemProps) => {
if (item.routes && item.routes.length) {
handle(item.routes);
} else {
flatMenus.push({
pathname: item.path,
name: item.name,
});
}
});
};
handle(menus);
return flatMenus;
};
4 创建模板:/src/models/exitMenus.ts
import type { menuTabProps } from '@/services/types/menu';
import { useState, useCallback } from 'react'
export default () => {
const [exitMenus, setExitMenus] = useState<menuTabProps[]>([]);
// 改变缓存菜单
const updateMenus = useCallback((menus: menuTabProps[]) => {
setExitMenus(menus);
}, []);
return {
exitMenus,
updateMenus,
};
};
5 文件位置:/src/global.less 插入样式
// 多标签窗口
.antLayoutAdminTabs {
width: 100%;
height: 40px;
display: block;
:global {
.ant-tabs {
top: 72px;
position: fixed;
padding: 0 16px;
width: 100%;
margin: -24px -24px 0;
background: #fff;
z-index: 18;
overflow: hidden;
height: 40px;
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
}
.ant-tabs-tab {
background: #ffffff !important;
border: 0 !important;
font-size: 14px !important;
border-bottom: 2px solid#ffffff !important;
padding: 8px 18px !important;
}
.ant-tabs-tab-active {
background: #e6f7ff !important;
color: #1890ff !important;
border-bottom: 2px solid#1890ff !important;
}
}
}
6 创建模板:/src/pages/layouts/commonLayout.tsx
import React, { useEffect, useState } from 'react';
import { Tabs } from 'antd';
import { history, useModel } from 'umi';
import { find } from 'lodash';
import { menuTabProps } from '@/services/types/menu';
import { handleMenusToFlat } from '@/utils/base';
import { KeepAlive, useAliveController } from 'react-activation';
import global from '@/global.less';
const CommonLayout = (props: any) => {
const { location, route } = props;
const { pathname } = location;
const [activeKey, setActiveKey] = useState<string>('');
const { dropScope } = useAliveController();
const { exitMenus, updateMenus } = useModel('exitMenus', (model) => ({
exitMenus: model.exitMenus,
updateMenus: model.updateMenus,
}));
const flatMenus = handleMenusToFlat(route.routes);
const noCachRoutes = ['/', '/user/login']; // 不需要缓存的路由
// console.log("2222222222222222222222222222222222222", route);
useEffect(() => {
// console.log(333, location, flatMenus);
if (noCachRoutes.includes(pathname)) return;
const arr: menuTabProps[] = exitMenus.filter((item: menuTabProps) => item.key !== pathname);
if (arr.length === exitMenus.length) {
const activeTab = find(flatMenus, (item) => item.pathname === pathname) || {};
const activeMenu: menuTabProps = {
label: activeTab.name,
key: pathname,
closable: exitMenus.length > 0, // 新增时,第一个页面不能删除
};
arr.push(activeMenu);
updateMenus(arr);
} else if (exitMenus.length === 1) {
// 删除时,只剩一个标签去掉删除图标
const data = exitMenus;
data[0].closable = false;
updateMenus(data);
}
setActiveKey(pathname);
}, [location]);
const onTabChange = (key: string) => {
history.push(key);
setActiveKey(key);
// console.log(key);
};
return (
<>
<div className={global.antLayoutAdminTabs}>
<Tabs
items={exitMenus}
onChange={onTabChange}
type='editable-card'
hideAdd={true}
activeKey={activeKey}
onEdit={(path: string) => {
// console.log(path, exitMenus, pathname);
let activePath = pathname;
const arr: menuTabProps[] = exitMenus.filter((item: menuTabProps, i: number) => {
if (item.key === path) {
// 获取前一个标签
activePath = exitMenus[i - 1].key;
}
return item.key !== path;
});
// 如果关闭当前标签,展示前一个标签
if (path === pathname) {
history.push(activePath);
}
// 关闭页签去掉缓存
dropScope(path);
updateMenus(arr);
}}
/>
</div>
<KeepAlive when={true} id={pathname} name={pathname} saveScrollPosition="screen" >
{props.children}
</KeepAlive>
</>
);
};
export default CommonLayout;
7 文件位置:/config/routes.ts 继承模板
{
path: '/',
component: './layouts/commonLayout',
flatMenu: true,
routes: [
// {
// path: '/welcome',
// name: '工作台',
// component: '@/pages/modules/welcome',
// }
]
},