需求比较复杂,但是也比较合理吧,网页里面的系统
把左侧菜单放一个component里面:
具体有关menu的误操作,上一篇有记录
把menu里面的点击的内容(activeKey,openKeys【这个我没放,根据当前路径去对比数据找到当前展开的menu】,当前的menu的url,key,name,因为tabs需要用到)都记录到 状态机里,也就是redux一类的
数据:
export default {
dashboard: {
url: '/dashboard',
name: '概览',
icon: 'Index',
key:'dashboard',
level:1,
},
newsinfo: {
url: '/newsinfo',
name: '一级菜单',
icon: 'Newsinfo',
key:'newsinfo',
level:1,
children:{
researchInfo:{
url: '/newsinfo/researchInfo',
name: '二级菜单',
icon: 'warning',
key: 'researchInfo',
level:2,
children:{
bondView: {
url: '/newsinfo/ResearchInfo/BondView',
name: '三级菜单', icon: 'eye',
level:3,
},
}
}
}
}
menu component下的代码
componentDidMount() {
const cururl = window.location.pathname;
//默认概览页
if (cururl === '/' || cururl === '' ) {
this.putActiveKey('/dashboard')
this.compareUrlOne('/dashboard');
} else {
this.putActiveKey(cururl)
this.compareUrlOne(cururl);
}
}
//循环一级key menuConfig即前面的数据,需要引入
compareUrlOne = (cururl) => {
const that = this;
Object.keys(menuConfig).forEach(function (keyp) {
const item = menuConfig[keyp]
if (item.url === cururl) {
//把地址和title存入状态机
that.onMenuClick({ route: cururl, title: item.name })
}
if (item && item.children) {
const childItem = item.children;
that.compareUrl(childItem, cururl, keyp);
}
})
}
//循环二级key找对应的openkeys
compareUrl = (obj, url, ...keyp) => {
this.defalutOpenkeys = [];
const that = this;
for (let i in obj) {
if (obj[i].url === url) {
that.defalutOpenkeys.push(...keyp);
that.setState({ openKeys: that.defalutOpenkeys })
that.onMenuClick({ route: url, title: obj[i].name, componentName: i })
break;
}
if (obj[i] && obj[i].children) {
const childItem = obj[i].children;
that.compareUrl(childItem, url, ...keyp, i);
}
}
}
//点击存入状态机,
onMenuClick = (data) => {
const { dispatch } = this.props;
dispatch({
type: 'publicmenu/clickMenu',
payload: data,
});
this.putActiveKey(data.route);
router.push(data.route);
}
return (
<Sider
collapsed={collapsed}
className="mymenu-layout"
width={250}
>
<Menu theme="dark"
defaultOpenKeys={this.state.openKeys}
defaultSelectedKeys={[curactiveKey]}
selectedKeys={[curactiveKey]}
mode="inline"
inlineIndent={25}
className={styles.sider_menu}
onOpenChange={this.onOpenChange}
{...defaultProps}
>
{menu}
</Menu>
{collapsed ? <Icon
className="collapse"
component={Packup} onClick={this.handleMenuCollapse}
/> :
<Icon
className="collapse"
component={PackDown} onClick={this.handleMenuCollapse}
/>}
</Sider>
状态机的部分代码publicmenu。js: 找个时间单独写这一块
export default {
namespace: 'publicmenu',
state: {
curactiveKey: '', //当前定位的menu的activekey
componentName:'', //需要存储当前的 模块的名称,keep-alive需要用到
collapsed: false, //菜单展开或收起
tabList: [
{ title: '概览', route: '/dashboard', key: '概览', default: true },
],
activeTab: '0', //当前定位的tab
},
effects: {
*fetchactiveKey({ payload, callback }, { select, put }) {
yield put({
type: 'activeKey',
payload: payload,
});
},
*fetchopenKeys({ payload, callback }, { put, select, call }) {
yield put({
type: 'openKeys',
payload: payload,
});
},
*clickMenu({ payload }, { put, select }) {
//拿到当前的tabList
const tabsList = yield select(state => {
return state.publicmenu.tabList;
});
//如果没有数据,这个因为需求不同,有的需要首页不能关闭,有的需要关闭,不能关闭这个tablist就有默认值,那他的length不可能为0
if(tabsList.length === 0){
const key ='概览';
yield put({
type: 'saveActiveTab',
payload: key.toString(),
});
yield put({
type: 'saveComponentName',
payload: 'dashboard',
});
}
let index = null;
//
tabsList.map((item, indexs) => {
if (item.route === payload.route) {
index = indexs;
}
});
if (index !== null) {
yield put({
type: 'saveActiveTab',
payload: tabsList[index].key,
});
yield put({
type: 'saveComponentName',
payload: tabsList[index].componentName,
});
} else {
const key = payload.title;
const name = payload.componentName;
tabsList.push({
...payload,
key: key.toString(),
});
yield put({
type: 'saveTabsList',
payload: tabsList,
});
yield put({
type: 'saveActiveTab',
payload: key.toString(),
});
yield put({
type: 'saveComponentName',
payload: name.toString(),
});
}
},
reducers: {
activeKey(state, { payload }) {
return {
...state,
curactiveKey: payload,
};
},
openKeys(state, { payload }) {
return {
...state,
curopenKeys: payload,
};
},
。。。
},
}
我把tabs跳转页面写入了,keep-alive 里面的provide也写在了里面
layout.js,其中tabs只是对tabs的头部进行了处理,其实content只是另外用路由去加载他的数据
<Layout className={styles.layout}>
<MenuList
pathname={pathname}
url={this.state.url}
/>
<Layout>
<Header >
<Tabs
tabBarGutter={1}
type="card"
onChange={this.onChange}
activeKey={activeTab}
>
{tabList.map(pane => (
<TabPane
tab={
<span>
{pane.title}
{pane.default ? (
''
) : (
<span>
{pane.title === '概览' ? '' : <Icon
type="close"
className = 'close-style'
onClick={e => this.closeOne(pane, e)}
/>}
</span>
)}
</span>
}
key={pane.key}
/>
))}
</Tabs>
</Header>
<Content className={styles.subLayout}>
<Provider>
{this.props.children}
</Provider>
</Content>
</Layout>
</Layout>
其中
嵌套路由下:
_layout.js 的内容
import React from 'react';
import { KeepAlive } from 'react-keep-alive';
import { connect } from 'dva';
import { Layout } from 'antd';
import {
Com,
} from '../Com';
@connect(({ publicmenu }) => ({ publicmenu }))
class NewsInfoRoute extends React.Component {
getComponentName = (name) => {
switch (name) {
case 'Com':
return <Com />;
default:
return <Com />;
}
}
render() {
const { publicmenu } = this.props;
return (
<Layout>
<KeepAlive name={publicmenu.componentName}>
{this.getComponentName(publicmenu.componentName)}
</KeepAlive>
</Layout>
);
}
}
export default NewsInfoRoute;
其中如果想要改动antd里面的样式,需要在global里面写代码
但是如果不想影响全局的css,那就在外层套用一个自己的css
使用的时候记得写成 className = ‘mymenu’ 而非 className = {style.mymenu}
:global {
.mymenu{
.ant-menu-item span, .ant-menu-submenu-title span{
position: relative;
z-index: 9;
}
}
}