IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React-View-UI组件库封装——Menu导航菜单 -> 正文阅读

[JavaScript知识库]React-View-UI组件库封装——Menu导航菜单

Menu菜单是提供给网站的路由跳转主菜单(通常),组件文档如图所示:
在这里插入图片描述
在这里插入图片描述
组件源码如下:

import React, { FC, useState, useEffect, memo, useCallback, useMemo } from 'react';
import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons';
import style from './index.module.less';

interface MenuProps {
  /**
   * @description 配置对象
   * @default {}
   */
  items: Array<RenderOptions>;
  /**
   * @description 自定义宽度
   * @default 220px
   */
  width?: string | number;
  /**
   * @description 深度模式
   * @default false
   */
  dark?: Boolean;
  /**
   * @description 手风琴
   * @default false
   */
  ableToggle?: Boolean;
  /**
   * @description 默认展开
   * @default false
   */
  defaultOpen?: Boolean;
  /**
   * @description 切换菜单回调函数
   */
  handleRouteChange?: Function;
}
interface MenuHeightProps {
  key: string;
  height: string;
  childNum: number | string;
  level: number | number;
  children?: Array<Object>;
}
interface RenderOptions {
  label: string;
  key: string | number;
  level?: string | number;
  icon?: JSX.Element | null;
  children?: Array<any> | null | undefined;
}

const Menu: FC<MenuProps> = (props) => {
  const [nowActiveMainKey, setNowActiveMainKey] = useState(''); //选中的一级菜单key
  const [nowActiveKey, setNowActiveKey] = useState(''); //选中的子菜单key
  const [parentMenuHeightList, setParentMenuHeightList] = useState<any>({}); //父菜单高度集合

  const { items, width, dark, ableToggle, defaultOpen, handleRouteChange } = props;

  useEffect(() => {
    const initList = initParentMenuHeight(items, {}, '');
    if (defaultOpen) {
      //默认展开
      for (var key in initList) {
        initList[key].height = initList[key].childNum + 1;
        if (initList[key].children.length > 0) {
          initList[key].children.map(
            (item: any) => (item.height = (item.childNum + 1) * 50 + 'px'),
          );
          initList[key].height += initList[key].children.reduce(
            (pre: MenuHeightProps, next: MenuHeightProps) => {
              return (pre.childNum as number) + (next.childNum as number);
            },
          );
        }
        initList[key].height = initList[key].height * 50 + 'px';
      }
    }
    setParentMenuHeightList(initList);
  }, []);
  useEffect(() => {
    handleRouteChange && handleRouteChange(nowActiveKey);
  }, [nowActiveKey]);
  const initParentMenuHeight = (
    item: Array<RenderOptions>,
    obj: any,
    fatherKey: string | number,
  ) => {
    //初始化父级菜单高度
    item.forEach((m) => {
      if (m.children) {
        if (m.level == 1) {
          obj[m.key] = {
            key: m.key,
            height: '50px',
            childNum: m.children.length,
            level: m.level,
            children: [],
          };
        } else {
          obj[fatherKey]?.children.push({
            key: m.key,
            height: '50px',
            childNum: m.children.length,
            level: m.level,
          });
        }
        initParentMenuHeight(m.children, obj, m.level && m.level == 1 ? m.key : '');
      }
    });
    return obj;
  };

  const toggleFirstMenu = (fMenu: RenderOptions, e: any) => {
    //点击父级菜单
    e.stopPropagation();
    const selectKey = fMenu.key;
    setParentMenuHeightList((old: any) => {
      old[selectKey].height =
        old[selectKey].height == '50px' ? (old[selectKey].childNum + 1) * 50 + 'px' : '50px';
      if (ableToggle) {
        //手风琴折叠
        if (old[selectKey].height !== '50px') {
          for (var key in old) {
            if (key !== selectKey) {
              old[key].height = '50px';
              if (old[key].children) {
                old[key].children.map((item: MenuHeightProps) => (item.height = '50px'));
              }
            }
          }
        }
      } else {
        //普通折叠
        if (old[selectKey].children) {
          old[selectKey].children.forEach((c: MenuHeightProps) => {
            c.height = '50px';
          });
        }
      }

      return JSON.parse(JSON.stringify(old));
    });
  };
  const toggleChildMenu = (cMenu: RenderOptions, e: any, fKey: string) => {
    //点击子级菜单
    if ((cMenu.level == 2 && !cMenu.children) || cMenu.level == 3) {
      setNowActiveMainKey(fKey);
      setNowActiveKey(cMenu.key as string);
    }
    if (cMenu.level == 2) {
      //二级菜单扩展切换
      setParentMenuHeightList((old: any) => {
        for (var key in old) {
          if (
            old[key].children &&
            old[key].children.findIndex((item: MenuHeightProps) => item.key == cMenu.key) !== -1
          ) {
            //找出是哪个一级菜单的children
            const childIndex = old[key].children.findIndex(
              (item: MenuHeightProps) => item.key == cMenu.key,
            );
            old[key].children[childIndex].height =
              old[key].children[childIndex].height == '50px'
                ? (old[key].children[childIndex].childNum + 1) * 50 + 'px'
                : '50px';
            let parentHeight = (old[key].childNum - old[key].children.length) * 50 + 50; //改变子菜单高度后统计父菜单高度
            parentHeight += old[key].children.reduce(
              (pre: MenuHeightProps, next: MenuHeightProps) => {
                return Number(pre.height.split('px')[0]) + Number(next.height.split('px')[0]);
              },
            );
            old[key].height = parentHeight;
          }
        }
        return JSON.parse(JSON.stringify(old));
      });
    }
    if (cMenu.level == 3) {
      for (var key in parentMenuHeightList) {
        if (
          parentMenuHeightList[key].children &&
          parentMenuHeightList[key].children.findIndex(
            (item: MenuHeightProps) => item.key == fKey,
          ) !== -1
        ) {
          setNowActiveMainKey(parentMenuHeightList[key].key);
        }
      }
    }
  };
  const firstMenuHeight = useCallback(
    (key) => {
      //第一级菜单高度
      if (parentMenuHeightList[key]) {
        return {
          height: parentMenuHeightList[key]?.height,
        };
      }
      return {
        height: '50px',
      };
    },
    [parentMenuHeightList],
  );
  const childMenuHeight = useCallback(
    (key) => {
      //第二级菜单高度
      for (var i in parentMenuHeightList) {
        const childIndex = parentMenuHeightList[i].children?.findIndex(
          (item: RenderOptions) => item.key == key,
        );
        if (childIndex !== -1) {
          return {
            height: parentMenuHeightList[i].children[childIndex].height,
          };
        }
      }
      return {
        height: '50px',
      };
    },
    [parentMenuHeightList],
  );
  const customWidth = useMemo(() => {
    if (width) {
      if (typeof width == 'string') {
        return {
          width: (width as string).includes('%') ? width : width + 'px',
        };
      } else if (typeof width == 'number') {
        return {
          width: width + 'px',
        };
      }
    }
    return {
      width: '220px',
    };
  }, [width]);

  const renderChildOptions = (childM: RenderOptions): JSX.Element | any => {
    //传入level为1的children,进行子项递归
    if (childM.children) {
      return childM.children.map((m) => {
        return (
          <div key={m.key}>
            <div
              className={nowActiveKey == m.key ? style.activeMenuOptions : style.childMenuOptions}
              style={{ ...childMenuHeight(m.key) }}
            >
              <div
                className={
                  m.children &&
                  m.children.findIndex((i: RenderOptions) => i.key == nowActiveKey) !== -1
                    ? style.activeFatherTitle
                    : style.fatherTitle
                }
                onClick={(e) => toggleChildMenu(m, e, childM.key as string)}
              >
                <span>{m.label}</span>
                {m.children &&
                  (childMenuHeight(m.key).height == '50px' ? (
                    <CaretDownOutlined />
                  ) : (
                    <CaretUpOutlined />
                  ))}
              </div>
              <div className={style.childMenuOptions} key={m.key}>
                {m.children && renderChildOptions(m)}
              </div>
            </div>
          </div>
        );
      });
    }
  };

  return (
    <div className={dark ? style.darkMenu : style.menu} style={customWidth}>
      {items.map((m) => {
        return (
          <div key={m.key}>
            <div className={style.menuOptions} style={firstMenuHeight(m.key)}>
              <div
                className={nowActiveMainKey == m.key ? style.activeFatherTitle : style.fatherTitle}
                onClick={(e) => toggleFirstMenu(m, e)}
              >
                <div className={style.left}>
                  <i>{m.icon}</i>
                  <span>{m.label}</span>
                </div>
                {firstMenuHeight(m.key).height == '50px' ? (
                  <CaretDownOutlined />
                ) : (
                  <CaretUpOutlined />
                )}
              </div>
              <>{m.children && renderChildOptions(m)}</>
            </div>
          </div>
        );
      })}
    </div>
  );
};

export default memo(Menu);

组件库线上地址:http://124.222.161.174:8080/#/common/menu
感谢阅览,终于要迎来10+组件了~自己的react UI库也是逐步完善起来了

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:27:19  更:2022-04-22 18:30:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:49:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码