文章前景
常见的后台管理系统中,通常是页面属性的局部刷新,下面我们仿照若依
(侧边布局),实现相关功能。
若依在线演示,antd-3x文档
组件调整
官方代码是以类组件来实现,本次我们修改为函数组件模式。
//官方示例
class SiderDemo extends React.Component {
state = {
collapsed: false,
};
toggle = () => {
this.setState({
collapsed: !this.state.collapsed,
});
};
}
//import {useState} from "react";
const SysMenu = (props)=>{
const [collapsed,setCollapsed] = useState(false);
const onCollapse = () => {
setCollapsed(!collapsed);
};
}
函数组件中由于生命周期的问题,无法直接对state进行修改,本次使用hook(useState)完成。
路由配置
按照umi的官方介绍介绍,我们修改src
下的全局路由,将前文提到的组件改为layouts的子组件,配置如下。
module.exports = [
{
path:"/",
component:"../layouts/index.js",
routes:[
{
exact: true,
path: '/practice/calculate',
component: '../pages/calculate/calculate.js'
},
...routeConsole(practice_routes)
]
},
];
组件传递
下面回到/src/layouts/index.js
中,我们把子组件作为孩子节点传递给SysMenu(导航)
,相关代码如下:
// 引入布局和子组件
import SysMenu from '../layouts/menu/SysMenu.js';
// 分配路由
const BasicRoute = (props) => {
return (
<SysMenu>
{props.children}
</SysMenu>
);
}
export default BasicRoute;
下面我们回到SysMenu中,BasicRoute
组件中,我们把配置的子路由信息作为SysMenu
的属性传递给了SysMenu
,因此可以通过{props.children}
方法拿到相关子组件信息。
const SysMenu = (props)=>{
const [collapsed,setCollapsed] = useState(false);
const onCollapse = () => {
setCollapsed(!collapsed);
};
return (
<Layout>
<Sider trigger={null} collapsible collapsed={collapsed}>
<div className={layoutModule.logo} >
</div>
<Menu theme="dark" mode="inline" defaultSelectedKeys={['practice']}>
//稍后配置
</Menu>
</Sider>
<Layout>
<Header style={{ background: '#fff', padding: 0 }}>
</Header>
<Content className={layoutModule.content}>
<div style={{ padding: 24, background: '#fff', minHeight: '90%' }}>
{props.children}
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
</Layout>
</Layout>
);
}
export default SysMenu;
将子组件信息放置在Content
标签下,这样就能实现页面的整体布局不变,而是局部内容刷新了。
菜单配置
因为umi是基于路由的单页面应用,路由的变化会导致页面的变化,在菜单配置中我们需要添Link属性,实现路径的跳转而发生页面的刷新。相关<Menu>
配置如下
<Menu theme="dark" mode="inline" defaultSelectedKeys={['practice']}>
<SubMenu
key="practice"
title={
<span>
<Icon type="build" />
<span>练习模块</span>
<Link to="/practice/calculate"/>
</span>
}
>
<Link to="/practice"/>
<Menu.Item key="calculator">
<Icon type="calculator"/>
<span >计算程序</span>
<Link to="/practice/calculate"/>
</Menu.Item>
<Menu.Item key="air" >
<Icon type="skin"/>
<span>中央空调</span>
<Link to="/practice/air"/>
</Menu.Item>
</SubMenu>
<SubMenu
key="practice"
title={
<span>
<Icon type="build" />
<span>信息管理</span>
<Link to="/practice/calculate"/>
</span>
}
>
<Menu.Item key="user" >
<Icon type="user"/>
<span>用户管理</span>
<Link to="/practice/user"/>
</Menu.Item>
</SubMenu>
{/*<Menu.Item key="1">*/}
{/* <Icon type="appstore" />*/}
{/* <span>practice</span>*/}
{/*</Menu.Item>*/}
</Menu>
其中defaultSelectedKeys表示默认打开的菜单。
动态路由
前面我们配置了路由地址,实际情况会根据用户的不同权限展示不同的菜单,下面我们将菜单抽取出一个专门的组件来动态处理。文件目录如下所示:
其中SysMenu
文件中菜单配置变化如下:
目前我们指定菜单属性只有5个属性(后台已封装为父子结构),分别为name
,url
,icon
,key
,children
,按照顺序依次表现为菜单名称,菜单路由,菜单图标,唯一key,菜单的子级节点。数据结构如下所示:
const menuList = [
{
name:'练习程序',
url:'#',
icon:'build',
key:'practice',
children:[
{
name:'计算程序',
url:'/practice/calculate',
icon:'calculator',
key:'calculate',
children:[],
},{
name:'中央空调',
url:'/practice/air',
icon:'skin',
key:'air',
children:[],
},
]
},{
name:'信息管理',
url:'#',
icon:'build',
key:'infoManage',
children:[
{
name:'计算程序',
url:'/infoManage/user',
icon:'user',
key:'user',
children:[],
},
]
},
];
MenuTree
组件整体结构如下,其中extractMenus方法
则是将后台返回的权限菜单进行转化为对应的配置。
const MenuTree = ()=>{
return(
<Menu theme="dark" mode="inline" defaultSelectedKeys={[menuList[0].key]}>
{extractMenus(menuList)}
</Menu>
);
}
export default MenuTree;
const extractMenus = (list) =>{
return list.map((item, index) => (
doExtractMenus(item)
));
}
//显示菜单项
const doExtractMenus = (item)=>{
if(item.children.length == 0)
{
return (
<Menu.Item key={item.key}>
<Icon type={item.icon}/>
<span>{item.name}</span>
<Link to={item.url}/>
</Menu.Item>
);
}
else
{
return (
<SubMenu key={item.key} title={
<span>
<Icon type={item.icon}/>
<span>{item.name}</span>
</span>
}>
{extractMenus(item.children)}
</SubMenu>
);
}
}
常见问题
- 布局很小
页面上的布局没有填充整个页面,可以通过下面的配置来解决问题。
/*
umi:全局约定样式
路径:umi-react/src/global.css,其中umi-react是根目录
*/
/*ID选择器*/
#root {
height: 100%;
}
/*!important用来覆盖antdui原有的css属性值*/
.ant-layout {
display: flex;
flex: auto;
flex-direction: column;
min-height: 100%;
background: #f0f2f5;
}