一个简单的动态菜单组件

一个简单的动态菜单组件插图
点击图片查看

https://mock.ezcomezgo.com/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E5%8A%A8%E6%80%81%E8%8F%9C%E5%8D%95%E7%BB%84%E4%BB%B6/

实现方法如下

Menu.jsx

import { useState } from 'react'
import './Menu.css'

function Menu() {
  const menus = [
    {
      title: 'Home',
      icon: 'home'
    },
    {
      title: 'search',
      icon: 'search'
    },
    {
      title: 'user',
      icon: 'user'
    },
    {
      title: 'Setting',
      icon: 'setting'
    }
  ]
  const [activeMenu, setActiveMenu] = useState(menus[0].title)
  const [current, setCurrent] = useState(0)

  return (
    <div className="Menu">
      <div className='items'>
        <div style={
          {
            transform: 'translateX(' + 350 / 4 * current + 'px)'
          }
        } className="pointer"></div>
        {
          menus.map((item, index) => {
            return (
              <span onClick={() => {
                if (activeMenu !== item.title) {
                  setActiveMenu(item.title, index)
                  setCurrent(index)
                }
              }} key={item.title} className={`item iconfont icon-${item.icon} ${activeMenu === item.title ? 'active' : ''}`}>
                <span className='title'>{item.title}</span>
              </span>
            )
          })
        }
      </div>
    </div>
  )
}

export default Menu

Menu.css

@font-face {
  font-family: "iconfont";
  /* Project id  */
  src: url('iconfont.ttf?t=1653709881240') format('truetype');
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-home:before {
  content: "\f0174";
}

.icon-setting:before {
  content: "\e78e";
}

.icon-user:before {
  content: "\e7ae";
}

.icon-search:before {
  content: "\e8ef";
}

.Menu {
  color: rgb(0, 0, 0);
  height: 50px;
  width: 350px;
  background-color: rgb(15, 136, 218);
  border-top-left-radius: 15px;
  border-top-right-radius: 15px;
  display: flex;
  position: relative;
}

.Menu .items {
  display: flex;
  width: 100%;
  height: 100%;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
  /* border: 1px solid red; */
}

.Menu .items .item {
  cursor: pointer;
  height: 100%;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  font-size: 1.5em;
  transition: .3s ease-out;
  position: relative;
}

.Menu .items .item .title {
  font-size: .5em;
  font-weight: bold;
  position: absolute;
  top: 50px;
  opacity: 0;
}

.Menu .pointer {
  transition: .1s ease-out;
  box-sizing: border-box;
  position: absolute;
  top: -30px;
  left: calc(350px / 4 / 2 - 50px / 2);
  width: 50px;
  height: 50px;
  border-radius: 50%;
  border: 5px solid rgb(255, 255, 255);
  background-color: rgb(25, 226, 69);
}

.Menu .items .active {
  transform: translateY(-30px);
  color: #fff;
}

.Menu .items .active .title {
  opacity: 1;
}