react: menuService

1、获取菜单对象

static findCurrentItem(items, currentState, currentItem) {
        _.forEach(items, function (item) {
            if (item.state === currentState) {
                currentItem.push(item);
            } else if (MenuService.hasChildItems(item)) {
                MenuService.findCurrentItem(item.childItems, currentState, currentItem);
            }
        })
    }

    static findParentItem(items, currentItem, parentItem) {
        const fatherItem = _.find(items, {id: currentItem.fatherId});
        if (_.isEmpty(fatherItem)) {
            _.forEach(items, function (item) {
                if (MenuService.hasChildItems(item)) {
                    MenuService.findParentItem(item.childItems, currentItem, parentItem);
                }
            })
        } else {
            parentItem.push(fatherItem);
        }
    }

    static hasChildItems(item) {
        return !!item.childItems && item.childItems.length > 0;
    }

getCurrentItem(menus, currentState) {
        const currentItem = [];
        MenuService.findCurrentItem(menus, currentState, currentItem);
        return currentItem[0];
    }

    getParentItem(menus, currentItem) {
        const parentItem = [];
        MenuService.findParentItem(menus, currentItem, parentItem);
        return parentItem[0];
    }

2、获取实际页面module

getModules(menuTree) {
        const modules = [];
        _.forIn(menuTree, function (value, key) {
            if (!_.isEmpty(value)) {
                const moduleItem = {};
                const moduleItems = [];
                _.set(moduleItem, 'type', key);
                MenuService.findModuleItem(moduleItems, value);
                _.set(moduleItem, 'state', moduleItems[0]);
                modules.push(moduleItem);
            }
        });
        return modules;
    }

    static findModuleItem(moduleItems, menuTreeValue) {
        _.forEach(menuTreeValue, function (item) {
            if (item.state.indexOf('.') !== -1) {
                moduleItems.push(_.get(item, 'state'));
            } else if (MenuService.hasChildItems(item)) {
                MenuService.findModuleItem(moduleItems, item.childItems);
            }
        })
    }

3、获取默认路由

getDefaultState(menuTree) {
        const modules = this.getModules(menuTree);
        if (!_.isEmpty(modules)) {
            return _.get(modules[0], 'state');
        }
    }

4、获取menus

getMenu() {
        return new Promise((resolve, reject) => {
            axiosService.request({
                url: '/api/menus',
                method: 'GET'
            }).then(res => {
                const menuTree = {};
                const navigators = {};
                _.forEach(res.data, function (item) {
                    _.set(menuTree, item.state, item.childItems);
                    _.set(navigators, item.state, item.name);
                });
                const menu = {
                    menuTree,
                    navigators,
                    defaultState: this.getDefaultState(menuTree),
                    modules: this.getModules(menuTree)
                };
                typeof resolve === 'function' && resolve(menu);
            }).catch(error => {
                typeof reject === 'function' && reject(error);
            })
        })
    }

    getSidebarMenu(menuTree, nav) {
        return _.result(menuTree, nav);
    }

menuTree: 集合,里面包含一个nav,一个对应该nav的菜单item

[{"nav01": [nav01.menus01]},{"nav02": [nav01.menus02]}];

navigators: 一个nav,一个对应nav的名字

[{"nav01": "nav01.name"},{"nav02": "nav01.name"}];

modules: 一个nav,一个对应nav的第一个路由

[{"nav01": "nav01.defaultState01"},{"nav02": "nav01.defaultState02"}];

redux menu data:

import React from "react";
import {connect} from "react-redux";
import {withRouter} from "react-router-dom";
import {Icon} from "antd";
import _ from "lodash";
import "./index.scss"

const mapStateToProps = state => {
    return {
        menuData: state.MenuReducer.data
    }
};

class Sidebar extends React.Component {

    constructor(props) {
        super(props);
        this.currentState = props.location.pathname;
        this.menus = _.result(props.menuData.menuTree, props.nav);
    }

    componentDidMount() {
        const defaultNavItem = this.getDefaultNavItem();
        if (defaultNavItem === undefined) {
            this.props.history.replace('/forbidden');
            return;
        }
        this.setActiveNavItem(defaultNavItem);
        this.openNavItem(defaultNavItem);
        if (this.hasChildItems(defaultNavItem)) {
            this.setActiveChildNavItem(defaultNavItem.childItems);
        }
    }

    getDefaultNavItem() {
        const currentState = this.currentState;
        return _.find(this.menus, function (navItem) {
            if (navItem.state === currentState || _.some(navItem.childItems, {state: currentState})) {
                return navItem;
            }
        })
    }

    setActiveNavItem(navItem) {
        if (this.hasChildItems(navItem)) {
            this.clearParentActiveStatus();
        } else {
            this.clearActiveStatusWithChildItems();
            navItem.isActive = true;
            if (!!navItem.state) {
                this.props.history.replace(navItem.state);
            }
        }
    }

    setActiveChildNavItem(childNavItems) {
        const currentState = this.currentState;
        this.clearActiveStatusWithChildItems();
        if (_.isArray(childNavItems)) {
            childNavItems.forEach(function (navItem) {
                navItem.isActive = navItem.state === currentState;
            });
        } else {
            childNavItems.isActive = true;
        }
    }

    openNavItem(navItem) {
        navItem.isOpen = this.hasChildItems(navItem);
        this.forceUpdate();
    }

    onOpenNavItem(navItem) {
        if (this.hasChildItems(navItem)) {
            navItem.isOpen = !navItem.isOpen;
        } else {
            navItem.isOpen = false;
        }
        this.forceUpdate();
    }

    clearParentActiveStatus() {
        this.menus.forEach(function (navItem) {
            navItem.isActive = false;
        })
    }

    clearActiveStatusWithChildItems() {
        this.menus.forEach(function (navItem) {
            navItem.isActive = false;
            navItem.childItems.forEach(function (childItem) {
                childItem.isActive = false;
            })
        })
    }

    hasChildItems(navItem) {
        return !!navItem.childItems && navItem.childItems.length > 0;
    }

    menuIcon(navItem) {
        return <Icon type={navItem.isOpen ? 'caret-down' : 'caret-right'}/>
    }

    openOrActiveClass(navItem) {
        const basic = "nav-item";
        const openClass = navItem.isOpen ? "is-open" : "";
        const activeClass = navItem.isActive ? "active" : "";
        return basic + " " + openClass + " " + activeClass;
    }

    activeClass(navItem) {
        const basic = "child-nav-item";
        const activeClass = navItem.isActive ? "active" : "";
        return basic + " " + activeClass;
    }

    render() {
        return (
            <aside className="app-sidebar">
                <ul className="list-unstyled menu">
                    {
                        this.menus && this.menus.map((navItem, index) => {
                            return (
                                <li key={'li_' + index} className={this.openOrActiveClass(navItem)}>
                                   <span key={'span_' + index}
                                         className="item-name nav-item-content"
                                         onClick={() => {
                                             this.setActiveNavItem(navItem);
                                             this.onOpenNavItem(navItem)
                                         }}>
                                       {this.hasChildItems(navItem) ? this.menuIcon(navItem) : null}
                                       {navItem.name}
                                   </span>
                                    {
                                        navItem.isOpen ?
                                            <ul key={'subMenu_ul'} className="list-unstyled sub-menus">
                                                {
                                                    navItem.childItems.map((childItem, itemIndex) => {
                                                        return (
                                                            <li key={'submenu_li_' + itemIndex}
                                                                className={this.activeClass(childItem)}
                                                                onClick={() => {
                                                                    this.setActiveChildNavItem(childItem);
                                                                    this.setActiveNavItem(childItem)
                                                                }}>
                                                                <a className="item-name">{childItem.name}</a>
                                                            </li>
                                                        )
                                                    })
                                                }
                                            </ul> : null
                                    }
                                </li>
                            )
                        })
                    }
                </ul>
            </aside>
        )
    }
}

export default withRouter(connect(mapStateToProps)(Sidebar));

scss:

@import "../../styles/varibles";

.app-sidebar {
  overflow: hidden;
  width: 180px;

  > ul > li {
    position: relative;
    font-size: $font-lg;
    border-bottom: $border;
    border-right: $border;
    border-left: $border;

    &:first-child {
      border-top: $border;
      border-top-right-radius: $border-radius;
      border-top-left-radius: $border-radius;
    }

    &:last-child {
      border-bottom-right-radius: $border-radius;
      border-bottom-left-radius: $border-radius;
    }
  }

  .active {
    color: $primary-color;
    font-weight: bold;
    border-left: 3px solid $primary-color;
    background-color: $item-active-bg-color;
    a {
      font-weight: bold;
      color: $primary-color;
    }
  }

  .nav-item {
    .item-name {
      margin-left: 30px;
      height: 50px;
      line-height: 50px;
    }
    .anticon {
      position: absolute;
      height: 50px;
      line-height: 50px;
      left: 7px;
      font-size: $font-sm;
      color: $title-color;
    }

    &.is-open {
      .anticon {
        color: $primary-color;
      }
      .nav-item-content {
        color: $title-color;
        font-weight: bold;
      }
    }
    &:hover {
      .anticon,
      .nav-item-content {
        color: $primary-color;
      }
    }
    &:active {
      .nav-item-content {
        color: $primary-color;
        font-weight: bold;
      }
    }
    .sub-menu {
      border-top: none;
      font-size: $font-sm;

      .item-name {
        height: 40px;
        line-height: 40px;
      }

      .child-nav-item.active {
        .item-name {
          color: $primary-color;
          font-weight: bold;
        }
      }
    }
  }
}

 

posted @ 2018-07-19 19:23  Nyan  阅读(591)  评论(0编辑  收藏  举报