白嫖了无尽岁月,我也来写个博客。希望能帮到你!
网上一些方案都是把官方模板替换成自己写的。本人的方案是在模板的基础上进行添砖加瓦,理解起来更容易!
解决思路是:
记录页面切换时的路由(onPageChange),在内容部分进行动态渲染(myhref)。
注:
使用useState对数组进行更新时,需要以新数组的形式对赋值。如:sethref([...array]);
/**
* Ant Design Pro v4 use `@ant-design/pro-layout` to handle Layout.
*
* @see You can view component api by: https://github.com/ant-design/ant-design-pro-layout
*/
import ProLayout, { DefaultFooter, SettingDrawer, getMenuData } from '@ant-design/pro-layout';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { Link, useIntl, connect, history } from 'umi';
import { Result, Button, Tabs } from 'antd';
import Authorized from '@/utils/Authorized';
import RightContent from '@/components/GlobalHeader/RightContent';
import { getMatchMenu } from '@umijs/route-utils';
import logo from '../assets/logo.svg';
const { TabPane } = Tabs;
const pagesNum = 2; // 设置页签数量
const noMatch = (
<Result
status={403}
title="403"
subTitle="Sorry, you are not authorized to access this page."
extra={
<Button type="primary">
<Link to="/user/login">Go Login</Link>
</Button>
}
/>
);
/** Use Authorized check all menu item */
const menuDataRender = (menuList) =>
menuList.map((item) => {
const localItem = {
...item,
children: item.children ? menuDataRender(item.children) : undefined,
};
return Authorized.check(item.authority, localItem, null);
});
const defaultFooterDom = (
<DefaultFooter copyright={`${new Date().getFullYear()} XXXX`} links={[]} />
);
const BasicLayout = (props) => {
const {
dispatch,
children,
settings,
location = {
pathname: '/',
},
route = {
routes: [],
},
} = props;
const [myhref, sethref] = useState([]);
const menuDataRef = useRef([]);
useEffect(() => {
if (dispatch) {
dispatch({
type: 'user/fetchCurrent',
});
}
}, []);
/** Init variables */
const handleMenuCollapse = (payload) => {
if (dispatch) {
dispatch({
type: 'global/changeLayoutCollapsed',
payload,
});
}
}; // get children authority
const authorized = useMemo(
() =>
getMatchMenu(location.pathname || '/', menuDataRef.current).pop() || {
authority: undefined,
},
[location.pathname],
);
const { formatMessage } = useIntl();
const { routes = [] } = route;
const { breadcrumb } = getMenuData(routes);
/**
* 记录切换路由历史
*/
const pageChange = (local) => {
const value = breadcrumb[local.pathname];
const array = myhref;
let flag = false; // 标识没有相同值
for (let i = 0; i < array.length; i += 1) {
if (value.key === array[i].key) {
flag = true;
}
}
if (!flag) {
if (array.length > pagesNum) {
array.splice(0, 1);
}
array.push(value);
sethref([...array]);
}
};
const onChange = (key) => {
for (let i = 0; i < myhref.length; i += 1) {
if (key === myhref[i].key) {
history.push(myhref[i].key);
break;
}
}
};
const onEdit = (targetKey, action) => {
const array = myhref;
for (let i = 0; i < myhref.length; i += 1) {
if (targetKey === myhref[i].key) {
array.splice(i, 1);
sethref([...array]);
break;
}
}
};
return (
<>
<ProLayout
logo={logo}
// formatMessage={formatMessage} 关闭语言国际化
{...props}
{...settings}
onPageChange={pageChange}
onCollapse={handleMenuCollapse}
onMenuHeaderClick={() => history.push('/')}
menuItemRender={(menuItemProps, defaultDom) => {
if (
menuItemProps.isUrl ||
!menuItemProps.path ||
location.pathname === menuItemProps.path
) {
return defaultDom;
}
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
}}
breadcrumbRender={(routers = []) => [
{
path: '/',
breadcrumbName: formatMessage({
id: 'menu.home',
}),
},
...routers,
]}
itemRender={(route, params, routes, paths) => {
const first = routes.indexOf(route) === 0;
return first ? (
<Link to={paths.join('/')}>{route.breadcrumbName}</Link>
) : (
<span>{route.breadcrumbName}</span>
);
}}
footerRender={() => {
if (settings.footerRender || settings.footerRender === undefined) {
return defaultFooterDom;
}
return null;
}}
menuDataRender={menuDataRender}
rightContentRender={() => <RightContent />}
postMenuData={(menuData) => {
menuDataRef.current = menuData || [];
return menuData || [];
}}
>
<Authorized authority={authorized.authority} noMatch={noMatch}>
<Tabs hideAdd type="editable-card" onChange={onChange} onEdit={onEdit}>
{myhref.map((pane) => (
<TabPane tab={pane.name} key={pane.key}></TabPane>
))}
</Tabs>
{children}
</Authorized>
</ProLayout>
<SettingDrawer
settings={settings}
onSettingChange={(config) =>
dispatch({
type: 'settings/changeSetting',
payload: config,
})
}
/>
</>
);
};
export default connect(({ global, settings }) => ({
collapsed: global.collapsed,
settings,
}))(BasicLayout);
以下是效果图: