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

2023-11-15

把左侧菜单放一个容器component里面:
把menu里面的相关API内容(activeKey,openKeys【这个我没放,根据当前路径去对比数据找到当前展开的menu】,当前的menu的url,key,name,因为tabs需要用到)都记录到 状态机里,也就是redux一类的

menu数据格式:

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跳转页面写入了layout.js, keep-alive插件下的provide组件 也写在了里面
其中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;
	     }
     }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • [LeetCode]二叉树题目总结

    LeetCode 二叉树习题个人总结 近一个月来 刷了不少LeetCode题目 但是总还是感觉提高的不多 自己最初想的一边做一边总结的初衷也没有正常执行 今晚静下心来 总结一下和二叉树有关的题目 基础题目 二叉树遍历 Binary Tree

随机推荐

  • 有哪些研究数据结构的好的方法?

    来源 我是码农 转载请保留出处和链接 本文链接 http www 54manong com id 17 研究数据结构是为了编写程序 编写程序是为了解决问题 用计算机求解一个现实问题 一般可用以下的问题求解模型加以描述 现实问题 数学模型 算
  • C++知识点——仿函数

    仿函数 并不是函数 却有着类似于函数的行为 简单地说就是重载括号运算符号 把对象当作一个函数用 仿函数拥有自己的数据成员 意味着仿函数拥有状态 include
  • 【MMDetection】bug记录

    bug1 if env cfg get cudnn benchmark AttributeError NoneType object has no attribute get 解决办法 配置文件缺少了env cfg信息 需要在config文
  • php error:0A000126:SSL routines::unexpected eof while reading

    文章目录 问题 解决 问题 file get contents https api weixin qq com sns jscode2session appid this gt appid secret this gt secret js
  • 32位/64位 libmysql.dll和libmysql.lib下载

    为了解决C MFC 32位程序不能连接64位MySQL数据库 需要用到32位的libmysql dll和libmysql lib 花了好久才找到 直接附上官网下载地址 https downloads mysql com archives c
  • aop中获取@PathVariable参数

    1 controller中的声明 2 aop中获取 RequestAttributes attributes RequestContextHolder getRequestAttributes ServletRequestAttribute
  • 【对比Java学Kotlin】数据类

    我们在 Java 里面会创建一些专门用于盛放数据的类 比如各种以 Bean Model 作为后缀结尾的类 这些类的成员变量通常是各种类型的数据 成员函数是 setter 和 getter 或者偷懒的同学直接把成员变量的可见性设置为 publ
  • 封装C++风格的rdkafka库

    项目中用到了kafka 系统是C 开发的 没有现成的可集成API 查阅github 发现有rdkafka 这个C库 挺好用的 但是 他依然不够简洁 因此 对他做了一下封装 ifndef KAFKAMQ H define KAFKAMQ H
  • frida的基本命令

    1 frida ps Ua 打印usb连接设备正在运行的进程 进程ID 进程名 包名 2 frida ps Uai 打印usb连接设备上所有的进程 进程ID 进程名 包名 3 frida加载js脚本 frida U l js 进程名或进程I
  • VScode 路径自动补全插件: Path Autocomplete、Path Intellisense

    目录 前言 路径自动补全插件 Path Autocomplete Path Intellisense 配置 编辑设置 json 顺路安利一个文件 icon 插件 Material Icon Theme 后记 Path Autocomplet
  • K8S生命周期---初始化容器(Init Container)

    Init 容器 Init 容器是一种特殊容器 在 Pod 内的应用容器启动之前运行 Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本 你可以在 Pod 的规约中与用来描述应用容器的 containers 数组平行的位置指定 I
  • 极氪汽车的云资源治理细探

    作者 极氪汽车吴超 前言 2021 年 极氪 001 迅速崭露头角 仅用 110 天便创下了首款车型交付量 最快破万 的纪录 2022 年 11 月 极氪 009 在短短 76 天内便率先完成了首批交付 刷新了中国豪华纯电品牌交付速度的纪录
  • go语言之tcp编程

    效果展示 原理图解 源码编写 go服务端的编写 package main import fmt net func processData conn net Conn 数据处理完之后关闭连接 defer conn Close for buf
  • 组合逻辑电路的设计(二) -- 五路输入呼叫显示电路和两个BCD8421码的加法运算电路

    一 实验任务及要求 1 设计要求 2题任选1题 鼓励2题都做 1 设计一个五路输入呼叫显示电路 5个数码开关分别模拟用户的输入信号 用户优先权按用户编号依次递减 即1号的优先权最高 5号最低 1至5号按键输入时 七段数码管对应显示1 2 3
  • ChatGPT写新闻-ChatGPT写文章

    ChatGPT写新闻 ChatGPT可以用于生成新闻稿件 但需要注意的是 由ChatGPT生成的新闻稿件可能存在语义 逻辑 事实准确性等方面的问题 因此需要进行人工审核和编辑 确保其准确性 下面是一个示例过程 大致了解如何使用ChatGPT
  • 计算机中丢失VCRUNTIME140_1怎么办,vcruntime140_1.dll的三个修复方法

    vcruntime140 1 dll是一个Windows系统文件 它是Microsoft Visual C Redistributable for Visual Studio 2019软件包的一部分 用于运行使用Visual C 开发的应用
  • 天地图WMTS地图瓦片下载

    最近在开发个人项目中遇到了这样一个问题 即 本地开发使用天地图在线地图服务 部署到线上时 突然想到 天地图提供的开放地图服务是需要申请秘钥key才能够使用的 而且需要连接外网 同时也是有访问次数限制的 那么 如果是在内网环境中如何进行迁移呢
  • [AWS] 利用serverless将WebSockets与AWS API Gateway和Lambda一起使用来构建实时应用程序

    1 WebSocket API 概念 WebSocket API由一个或多个路由组成 路由选择表达式用于确定特定请求应使用的路由 该选择将在请求中提供 根据请求对表达式进行求值 以产生与您的路线的routeKey值之一相对应的值 例如 如果
  • jsp页面设置UTF-8

    在我们安装好Eclipse中 新建jsp页面的时候我们总是会需要编码格式 现在我来介绍一个方式 使我们新建的jsp默认是UTF 8 1 首先我们需要在window gt preterences 2 选择我们的web选项中的jsp Files
  • antd+umi 嵌套路由_layout.js及antd tabs menus共同使用,实现点击菜单打开一个tabs页面并跳转路由,需要keep-alive实现数据缓存

    把左侧菜单放一个容器component里面 把menu里面的相关API内容 activeKey openKeys 这个我没放 根据当前路径去对比数据找到当前展开的menu 当前的menu的url key name 因为tabs需要用到 都记