React 实现二级菜单

用react实现一个二级菜单 应该是怎样的结构

阅读 15k
5 个回答

很快的写了一个示例代码,但可能不是最好的作法,css网上随手抓的,组件名也是临时取的不精准,只是提供一个思路。其实有很多已经写好的漂亮菜单组件可直接用,或是直接用纯CSS菜单作法会比较简单,自己写大概纯研究用。

用两个state中的值来控制第一级与第二级菜单项被选中的状态,简单地用数组索引代表被选中的菜单项,-1代表目前没有任何菜单项被选中。选中用MouseOver事件,没选中用MouseLeave事件。第一级菜单项直接用索引值切换选中,第二级用事件获取data-id与第一级菜单的索引值合并来setState这样。

代码演示长这样:

DEMO

index.html,主要里面有菜单的css,网上这里复制来用的:

<style>
ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    background-color: #333;
}

li {
    float: left;
}

li a {
    display: inline-block;
    color: white;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
}

.submenu-hidden {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
}

.submenu-show {
    display: block;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
}

.submenu-show a {
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
    text-align: left;
}

.submenuitem-hover {
  background-color: red;
}

.menu-hover {
  background-color: green;
}

</style>

App.js,主组件,集成第一级菜单,所有事件触发方法都在里面:

import React from 'react'
import MenuLevel from './MenuLevel'

const menuitems = [
  {
    text: 'Test 1',
    url: 'http://qq.com',
    submenu: [
      {
        text: '1 Child Test 1',
        url: 'http://qq.com',
      },
      {
        text: '1 Child Test 2',
        url: 'http://qq.com',
      },
    ]
  },
  {
    text: 'Test 2',
    url: 'http://qq.com',
    submenu: [
      {
        text: '2 Child Test 1',
        url: 'http://qq.com',
      },
      {
        text: '2 Child Test 2',
        url: 'http://qq.com',
      },
    ]
  },
  {
    text: 'Test 3',
    url: 'http://qq.com',
    submenu: []
  }
]

class App extends React.Component {
  constructor() {
    super()

    this.state = {
      showMenuItem: -1,
      showSubMenuItem: -1,
    }
  }

  handleMenuLevelHover = (index) => {
    this.setState({ showMenuItem: index })
  }

  handleMenuLevelLeave = () => {
    this.setState({ showMenuItem: -1 })
  }

  handleSubMenuLevelHover = (index, e) => {
    this.setState({
      showMenuItem: index,
      showSubMenuItem: +e.target.attributes.getNamedItem('data-id').value
    })
  }

  handleSubMenuLevelLeave = (e) => {
    this.setState({ showSubMenuItem: -1 })
  }

  render() {
    return (
      <ul>
        {
          menuitems.map((level, index) => (
             <MenuLevel
               text={level.text}
               url={level.url}
               key={index}
               index={index}
               onMouseOver={() => { this.handleMenuLevelHover(index) }}
               onMouseLeave={this.handleMenuLevelLeave}
               onSubItemMouseOver={(e) => { this.handleSubMenuLevelHover(index, e) }}
               onSubItemMouseLeave={this.handleSubMenuLevelLeave}
               showSubMenuItem={this.state.showSubMenuItem}
               showMenuItem={this.state.showMenuItem}
             >
               {level.submenu}
             </MenuLevel>
         ))
       }
      </ul>
    )
  }
}

export default App

MenuLevel.js,第一级菜单项目用的:

import React from 'react'
import SubMenuItem from './SubMenuItem'

const MenuLevel = (props) => (
  <li
    onMouseOver={props.onMouseOver}
    onMouseLeave={props.onMouseLeave}
    className={(props.showMenuItem === props.index) ? 'menu-hover' : ''}
    >
    <a href={props.url}>{props.text}</a>
    <div className={(props.showMenuItem === props.index) ? 'submenu-show' : 'submenu-hidden'}>
      {
        props.children.map((item, index) => (
          <SubMenuItem
            text={item.text}
            key={item.text + index}
            url={item.url}
            index = {index}
            showSubMenuItem={props.showSubMenuItem}
            onMouseOver={props.onSubItemMouseOver}
            onMouseLeave={props.onSubItemMouseLeave}
          />
        ))
      }
    </div>
  </li>
)

export default MenuLevel

SubMenuItem.js,第二级菜单项目用的:

import React from 'react'

const SubMenuItem = (props) => (
    <a
      href={props.url}
      data-id = {props.index}
      onMouseOver={props.onMouseOver}
      onMouseLeave={props.onMouseLeave}
      className={(props.showSubMenuItem === props.index) ? 'submenuitem-hover' : '' }
      >
      {props.text}
    </a>
)

export default SubMenuItem

注: e.target.attributes.getNamedItem('data-id').value可改为e.target.getAttribute('data-id')e.target.dataset.id

const nav = [
    {
        name: "菜单1",
        children: [
            {
                child: "子菜单1"
            },
            {
                child: "子菜单2"
            },
        ]
    },
    {
        name: "菜单2",
        children: [
            {
                child: "子菜单3"
            },
            {
                child: "子菜单4"
            },
        ]
    }
]

constructor(props) {
    super(props)
    this.state = {
        isShow: false
    }
}

render() {
    return (
        <ul>
            {
                nav && nav.map(e => {
                    return (
                        <li onClick={() => this.setState({isShow: true})}>
                            <a>{e.name}</a>
                            {
                                isShow && <div>
                                {
                                    e.children && e.children.map(k => {
                                        return (
                                           <span>{k.child}</span> 
                                        )
                                    })
                                }
                            </div>
                            }
                        </li>
                    )
                })
            }
        </ul>
    )
}

建议用ant design,里面有现成的二级菜单组件

没思路,如果不用dom操作怎么实现呢?

PC前端能用ant, 改样式,改死人。 这种教程应该多出点(虽然我还是没看懂)

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题