antd+umi 嵌套路由_layout.js及antd tabs menus共同使用,实现点击菜单打开一个tabs页面并跳转路由,需要keep-alive实现数据缓存

需求比较复杂,但是也比较合理吧,网页里面的系统

把左侧菜单放一个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}&nbsp;&nbsp;
                                        {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;
	     }
     }
}

你可能感兴趣的:(前端学习)