效果图

JS
import {
useState, Fragment } from 'react';
import styles from './style.less'
import pu from '@/assets/common/pu.png'
import itemImg from '@/assets/common/item.png'
import itemActiveImg from '@/assets/common/itemActive.png'
import gl from '@/assets/common/gl.png'
import jy from '@/assets/common/jy.png'
import kj from '@/assets/common/kj.png'
import ms from '@/assets/common/ms.png'
import ty from '@/assets/common/ty.png'
import wgbj from '@/assets/common/wgbj.png'
import wgll from '@/assets/common/wgll.png'
import wl from '@/assets/common/wl.png'
import ws from '@/assets/common/ws.png'
import gy from '@/assets/common/gy.png'
import mt from '@/assets/common/mt.png'
import hd from '@/assets/common/hd.png'
import tcc from '@/assets/common/tcc.png'
import xfs from '@/assets/common/xfs.png'
import bns from '@/assets/common/bns.png'
import ggcs from '@/assets/common/ggcs.png'
import ld from '@/assets/common/ld.png'
import wushui from '@/assets/common/wushui.png'
import xhd from '@/assets/common/xhd.png'
import ysss from '@/assets/common/ysss.png'
import gy_Active from '@/assets/common/gy_Active.png'
import mt_Active from '@/assets/common/mt_Active.png'
import hd_Active from '@/assets/common/hd_Active.png'
import tcc_Active from '@/assets/common/tcc_Active.png'
import xfs_Active from '@/assets/common/xfs_Active.png'
import bns_Active from '@/assets/common/bns_Active.png'
import ggcs_Active from '@/assets/common/ggcs_Active.png'
import ld_Active from '@/assets/common/ld_Active.png'
import wushui_Active from '@/assets/common/wushui_Active.png'
import xhd_Active from '@/assets/common/xhd_Active.png'
import ysss_Active from '@/assets/common/ysss_Active.png'
import topGy from '@/assets/common/popBox/topGy.png'
import topMt from '@/assets/common/popBox/topMt.png'
import topHd from '@/assets/common/popBox/topHd.png'
import topTcc from '@/assets/common/popBox/topTcc.png'
import topXfs from '@/assets/common/popBox/topXfs.png'
import topBns from '@/assets/common/popBox/topBns.png'
import topGgcs from '@/assets/common/popBox/topGgcs.png'
import topLd from '@/assets/common/popBox/topLd.png'
import topWushui from '@/assets/common/popBox/topWushui.png'
import topXhd from '@/assets/common/popBox/topXhd.png'
import topYsss from '@/assets/common/popBox/topYsss.png'
const navData = [
{
name: '网格部件', id: 1, rotate: 0, child: [
{
name: '公园', id: 1, img: gy, activeImg: gy_Active, topImg: topGy },
{
name: '码头', id: 2, img: mt, activeImg: mt_Active, topImg: topMt },
{
name: '涵洞', id: 3, img: hd, activeImg: hd_Active, topImg: topHd },
{
name: '停车场', id: 4, img: tcc, activeImg: tcc_Active, topImg: topTcc },
{
name: '消防栓', id: 5, img: xfs, activeImg: xfs_Active, topImg: topXfs },
{
name: '避难所', id: 6, img: bns, activeImg: bns_Active, topImg: topBns },
{
name: '公共厕所', id: 7, img: ggcs, activeImg: ggcs_Active, topImg: topGgcs },
{
name: '路灯', id: 8, img: ld, activeImg: ld_Active, topImg: topLd },
{
name: '污水', id: 9, img: wushui, activeImg: wushui_Active, topImg: topWushui },
{
name: '信号灯', id: 10, img: xhd, activeImg: xhd_Active, topImg: topXhd },
{
name: '雨水设施', id: 11, img: ysss, activeImg: ysss_Active, topImg: topYsss },
],
img: wgbj
},
{
name: '网格力量', id: 2, ysss: gy, rotate: 40, child: [
{
name: '网格员', img: gy, id: 1 },
{
name: '保洁员', img: gy, id: 2 },
{
name: '律师', img: gy, id: 3 },
{
name: '警官', img: gy, id: 4 },
{
name: '法官', img: gy, id: 5 },
{
name: '检察官', img: gy, id: 6 }
],
img: wgll
},
{
name: '文旅', id: 3, rotate: 80, img: wl },
{
name: '民生', id: 4, rotate: 120, img: ms },
{
name: '管理', id: 5, rotate: 160, img: gl },
{
name: '体育', id: 6, rotate: 200, img: ty },
{
name: '科技', id: 7, rotate: 240, img: kj },
{
name: '教育', id: 8, rotate: 280, img: jy },
{
name: '卫生', id: 9, rotate: 320, img: ws },
]
const index = () =>
{
const [isShow, setIsShow] = useState(false)
const [rotate, setRotate] = useState(0)
const [menuData, setMenuData] = useState(navData[0].child)
const [navDataActive, setNavDataActive] = useState(1)
const [menuDataActive, setMenuDataActive] = useState(null)
const handleMouse = (flag) =>
{
return () =>
{
setIsShow(flag)
}
}
const navClick = (data, rotate) =>
{
setNavDataActive(data.id)
setMenuData(data.child)
setMenuDataActive(null)
}
const menuClick = (data) =>
{
setMenuDataActive(data.id)
}
return (
<Fragment>
<div onMouseLeave={
handleMouse(false)} style={
{
transition: 'all 1s' }} className={
isShow ? styles.container : styles.containerActive}>
<div className={
styles.togglerContainers}>
<img style={
isShow ? {
transform: 'scale(1)', transition: 'all 1s' } : {
transform: 'scale(.8)', transition: 'all 1s' }} onMouseEnter={
handleMouse(true)} src={
pu} alt="" />
</div>
<div style={
{
transform: `rotate(-${
rotate}deg)`, transition: 'all 1s' }} className={
isShow ? styles.menuWarp : styles.menuWarpActive}>
<nav className={
styles.menu} >
<ul >
{
navData.map((data, index) => (
<li style={
isShow ? {
transform: `rotate(${
data.rotate}deg) translateX(-150px)` } : null} key={
index} className={
`${
styles.menu_item} ${
isShow && styles.menu_item_active} `} >
<a style={
navDataActive === data.id ? {
backgroundImage: `url(${
itemActiveImg} )`, backgroundSize: '100% 100%', transform: `rotate(-${
data.rotate}deg)`, transition: 'all 1s' } : {
backgroundImage: `url(${
itemImg} )`, backgroundSize: '100% 100%', transform: `rotate(-${
data.rotate}deg)`, transition: 'all 1s' }} onClick={
() => {
navClick(data, data.rotate) }}>
<img style={
{
width: '20px', height: '20px' }} src={
data.img} alt={
data.name} />
<span> {
data.name}</span>
</a>
</li>
))
}
</ul>
</nav>
</div>
<div >
{
menuData?.map((data, index) => (
<div style={
isShow ? {
transform: `rotate(${
360 / menuData.length * index}deg) translateX(-270px)` } : null} key={
index} className={
`${
styles.menu_item} ${
isShow && styles.menu_item_active} `} >
<a style={
menuDataActive === data.id ? {
flexFlow: 'column', backgroundImage: `url(${
itemActiveImg} )`, backgroundSize: '100% 100%', transform: `rotate(-${
360 / menuData.length * index}deg)`, transition: 'all 1s' } : {
flexFlow: 'column', backgroundImage: `url(${
itemImg} )`, backgroundSize: '100% 100%', transform: `rotate(-${
360 / menuData.length * index}deg)`, transition: 'all 1s' }} onClick={
() => {
menuClick(data, index) }}>
<img style={
{
width: '34px', height: '32px' }} src={
menuDataActive === data.id ? data.activeImg : data.img} alt={
data.name} />
<span> {
data.name}</span></a>
</div>
))}
</div>
</div >
</Fragment>
);
};
export default index
CSS
.container,
.containerActive {
margin: auto;
position: relative;
width: 700px;
height: 700px;
background: url('~@/assets/common/menu2.png') no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
pointer-events: auto;
width: 700px;
height: 700px;
background-size: 100% 100%;
.menuWarp,
.menuWarpActive {
width: 400px;
height: 400px;
background-color: red;
background: url('~@/assets/common/menu2.png') no-repeat;
background-size: 100% 100%;
}
.menuWarpActive {
width: 210px;
height: 210px;
background-color: red;
background: url('~@/assets/common/menu2.png') no-repeat;
background-size: 100% 100%;
}
.togglerContainers {
position: absolute;
display: block;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
// width: 40px;
// height: 40px;
width: 210px;
height: 210px;
z-index: 2;
cursor: pointer;
img {
width: 210px;
height: 210px;
}
}
.menu_toggler {
width: 100%;
height: 5px;
display: block;
z-index: 1;
border-radius: 2.5px;
background: rgba(255, 255, 255, 0.7);
transition: transform 0.5s, top 0.5s;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.menu_toggler_active {
width: 100%;
height: 5px;
display: block;
z-index: 1;
border-radius: 2.5px;
background: rgba(255, 255, 255, 1);
transition: transform 0.5s, top 0.5s;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
&::before,
&::after {
width: 40px;
height: 5px;
display: block;
z-index: 1;
border-radius: 2.5px;
background: rgba(255, 255, 255, 1);
transition: transform 0.5s, top 0.5s;
content: "";
position: absolute;
left: 0;
}
&::after {
top: -10px;
}
&::before {
top: 10px;
}
}
.menu_toggler::before,
.menu_toggler::after {
width: 40px;
height: 5px;
display: block;
z-index: 1;
border-radius: 2.5px;
background: rgba(255, 255, 255, 0.7);
transition: transform 0.5s, top 0.5s;
content: "";
position: absolute;
left: 0;
}
.menu_toggler::before {
top: 10px;
}
.menu_toggler::after {
top: -10px;
}
// 活跃的按钮
.menu_item_active {
opacity: 1 !important;
}
.menu_item_active:nth-child(1) {
transform: rotate(0deg) translateX(-110px);
}
.menu_item_active:nth-child(2) {
transform: rotate(60deg) translateX(-110px);
}
.menu_item_active:nth-child(3) {
transform: rotate(120deg) translateX(-110px);
}
.menu_item_active:nth-child(4) {
transform: rotate(180deg) translateX(-110px);
}
.menu_item_active:nth-child(5) {
transform: rotate(240deg) translateX(-110px);
}
.menu_item_active:nth-child(6) {
transform: rotate(300deg) translateX(-110px);
}
.menu_item_active:nth-child(1) a {
transform: rotate(0deg);
}
.menu_item_active:nth-child(2) a {
transform: rotate(-60deg);
}
.menu_item_active:nth-child(3) a {
transform: rotate(-120deg);
}
.menu_item_active:nth-child(4) a {
transform: rotate(-180deg);
}
.menu_item_active:nth-child(5) a {
transform: rotate(-240deg);
}
.menu_item_active:nth-child(6) a {
transform: rotate(-300deg);
}
.menu_item {
position: absolute;
display: block;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
width: 80px;
height: 80px;
opacity: 0;
transition: 0.5s;
}
.menu_item a {
// display: block;
// width: inherit;
// height: inherit;
// line-height: 80px;
// color: rgba(255, 255, 255, 0.7);
// background: rgba(255, 255, 255, 0.2);
// border-radius: 50%;
// text-align: center;
// text-decoration: none;
// font-size: 16px;
// transition: 0.2s;
// font-weight: 700;
justify-content: space-evenly;
padding: 8px;
display: flex;
width: inherit;
height: inherit;
color: rgba(255, 255, 255, 0.7);
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
text-align: center;
text-decoration: none;
font-size: 16px;
transition: 0.2s;
font-weight: 700;
align-items: center;
&:hover {
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3);
color: #fff;
background: rgba(255, 255, 255, 0.3);
// font-size: 18px;
}
}
}
.containerActive {
width: 700px;
height: 700px;
background: transparent;
}