css扇形菜单动画效果

 菜单组件 IntelligentAnalysis.vue

中间圆形区域可以换个图片

<template>
  <div class="intel-analysis">
    <div class="info" :class="{ 'close-animation': !showMenu }">
      <div class="middle"></div>
      <div class="text-info">
        <div v-for="(item, index) in list" :key="index">
          <div :class="`item ${item.type === currentType ? 'active' : ''}`"
            :style="{ rotate: `${item.rotate}deg`, left: item.left, top: item.top, }" @click="handleClick(item, index)">
            <div style="width: 10px;height: 11px;">
              <div :class="`${item.type === currentType && list2.length > 0 ? 'triangle' : ''}`"></div>
            </div>
            <div class="text">{{ item.text }}</div>
            <div class="icon">
              <img :src="item.icon" alt="">
            </div>
          </div>

        </div>
      </div>
    </div>
    <div class="info-sec-bg"></div>
    <div class="info-sec" ref="infoSecRef">
      <div v-for="(item, index) in list2" :key="index">
        <div :class="`citem ${item.type === currentType2 ? 'active' : ''}`"
          :style="{ rotate: `${item.rotate}deg`, left: item.left, top: item.top, }" @click="handleClick2(item, index)">
          <div class="text">{{ item.text }}</div>
        </div>
      </div>
    </div>

  </div>
</template>

<script>
import { defineComponent, onMounted, reactive, toRefs, watch } from 'vue'
import temp from '@/assets/imgs/supervisionGIS/temp.png'

export default defineComponent({
  name: 'IntelligentAnalysis',
  components: {
  },
  props: {
    showMenu: {
      type: Boolean,
      default: false
    }
  },
  emits: ['showMenu'],
  setup(props, { emit }) {
    const state = reactive({
      show: false,
      list: [
        {
          type: 'eng',
          icon: temp,
          text: '节能效果',
          // rotate: '8deg',
        },
        {
          type: 'ctrl',
          icon: temp,
          text: '节能效果',
          // rotate: '-11deg',
        },
        {
          type: 'engZhenduan',
          icon: temp,
          text: '节能效果',
          // rotate: '-33deg',
        },

        {
          type: 'secondNet',
          icon: temp,
          text: '节能效果',
          // rotate: '-56deg',
        },
        {
          type: 'comcell',
          icon: temp,
          text: '节能效果',
          // rotate: '-90deg',
        },
        // {
        //   type: 'comcell',
        //   icon: temp,
        //   text: '投诉re区',
        //   rotate: '-90deg',
        // }
      ],
      list2: [
        {
          type: 'eng2',
          icon: temp,
          text: '节能效果',
          // rotate: '8deg',
        },
        {
          type: 'ctrl2',
          icon: temp,
          text: '节能效果',
          // rotate: '-11deg',
        },
        {
          type: 'engZhenduan2',
          icon: temp,
          text: '节能效果',
          // rotate: '-33deg',
        },
        {
          type: 'engZhenduan2',
          icon: temp,
          text: '节能效果',
          // rotate: '-33deg',
        },
        // {
        //   type: 'engZhenduan2',
        //   icon: temp,
        //   text: '能耗诊治',
        //   // rotate: '-33deg',
        // },
        // {
        //   type: 'engZhenduan2',
        //   icon: temp,
        //   text: '能耗诊治',
        //   // rotate: '-33deg',
        // },
        // {
        //   type: 'engZhenduan2',
        //   icon: temp,
        //   text: '能耗诊治',
        //   // rotate: '-33deg',
        // },
        // {
        //   type: 'engZhenduan2',
        //   icon: temp,
        //   text: '能耗诊治',
        //   // rotate: '-33deg',
        // },
        // {
        //   type: 'engZhenduan2',
        //   icon: temp,
        //   text: '能耗诊治',
        //   // rotate: '-33deg',
        // },
      ],
      currentType: '',
      currentType2: '',
      infoSecRef: null,
    })
    const methods = {
      // 点击具体内容
      handleClick(item, index) {
        state.currentType = item.type
        let domSec = document.querySelector('.info-sec')
        let domBg = document.querySelector('.info-sec-bg')
        domSec.style.display = 'block'

        if (state.list2.length > 0) {
          domBg.style.display = 'block'
        }
        // 二级菜单扇形
        switch (state.list2.length) {
          case 1:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 42%, 0% 51%)'
            break;
          case 2:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 41%, 0% 60%)'
            break;
          case 3:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 41%, 0% 70%)'
            break;
          case 4:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 41%, 0% 82%)'
            break;
          case 5:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 41%, 0% 96%)'
            break;
          case 6:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 41%, 0% 116%)'
            break;
          case 7:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 41%, 0% 148%)'
            break;
          case 8:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 41%, 0% 215%)'
            break;
          case 9:
            domSec.style.clipPath = 'polygon(50% 50%, 0% 41%, 0% 484%)'
            break;
          default:
            break;
        }

        if (state.list2.length !== 1) {
          // 计算二级菜单度数的一半
          const num = -(((state.list2.length - 1) * 10) / 2)

          if (index === 0) {
            // 点第一个一级菜单时,二级菜单角度不变
            domSec.style.rotate = `${item.rotate - 3}deg`

          } else if (index === state.list.length - 1 && state.list.length > 1) {
            // 点最后一个一级菜单时,二级菜单角度要往回拉全部度数
            domSec.style.rotate = `${item.rotate - (2 * num) + 5}deg`

          } else {
            if (state.list2.length < 7) {
              // 点中间的一级菜单时,二级菜单角度要往回拉全部度数的一半
              domSec.style.rotate = `${item.rotate - num}deg`
            } else {
              if (index === 1) {
                domSec.style.rotate = `${item.rotate - num - (15)}deg`

              } else if (index === state.list.length - 2) {
                domSec.style.rotate = `${item.rotate - num - (-20)}deg`

              } else {
                domSec.style.rotate = `${item.rotate - num}deg`
              }
            }
          }
        } else {
          // 二级菜单只有一个时,旋转一级菜单的角度
          domSec.style.rotate = `${item.rotate}deg`
        }

        domSec.style.transition = '0.5s'
        // emit('pageTypeChange', item)
      },
      handleClick2(item) {
        state.currentType2 = item.type
        emit('getCurMenu', item)
      },
    }
    watch(() => props.showMenu, () => {
      console.log(props.showMenu, '---props.showMenu--');
      if (!props.showMenu) {
        state.currentType = ''
        state.currentType2 = ''
        state.infoSecRef.style.display = 'none'

      }
    })
    onMounted(() => {
      state.list.forEach((item, index) => {
        const length = state.list.length
        // item.rotate = `-${(120 / length * index)}`
        item.rotate = `-${((100 / (length - 1)) * index)}`
        if (index === length - 1) {
          item.rotate = -100
        }
        if (index === 0) {
          item.rotate = 0
        }
        console.log(item.rotate, '--margin-left--');
      })
      state.list2.forEach((item, index) => {
        const length = state.list2.length
        if (index === 0) {
          item.rotate = 0
        } else {
          item.rotate = -(10 * index)
        }
        console.log(item.rotate, '--item.rotate--');
      })
    })
    return {
      ...toRefs(state),
      ...methods,
    }
  }
})
</script>

<style scoped lang="less">
.intel-analysis {
  .info {
    width: 320px;
    height: 320px;
    border-radius: 50%;
    // width: 206px;
    // height: 206px;
    // border-radius: 0 0 0 206px;
    background: linear-gradient(160deg, rgba(3, 46, 116, 0) 0%, #032E74 22%, rgba(3, 46, 116, 0.99) 52%, #032E74 80%, rgba(3, 46, 116, 0) 100%);
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 3;
    animation: show 0.5s;


    .middle {
      width: 80px;
      height: 80px;
      background-color: var(--gdky-layout-bg);
      border-radius: 50%;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      cursor: pointer;
    }
  }

  .item {
    display: flex;
    align-items: center;
    font-size: 14px;
    color: var(--gdky-second-content-color);
    padding-right: 55px;
    margin-bottom: 16px;
    cursor: pointer;
    position: absolute;
    left: -5%;
    /* 居中 */
    top: 44%;
    /* 居中 */
    transform: translate(7%, -50%);
    // /* 居中 */
    transform-origin: center right;
    z-index: 4;

    &:hover {
      color: #3C74CF;
    }

    &.active {
      font-weight: 600;
      color: #3C74CF;
    }

    .text {
      margin-left: 18px;
    }

    .triangle {
      width: 0;
      height: 0;
      border-left: 5px solid transparent;
      /* 左边 */
      border-right: 5px solid transparent;
      /* 右边 */
      border-bottom: 10px solid #ffcc00;
      /* 底边,根据等边三角形计算得到 */
      transform: rotate(-90deg);
    }

    .icon {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 28px;
      height: 28px;
      margin-left: 16px;
      background: linear-gradient(293deg, #032E74 0%, #001941 100%);
      border-radius: 50%;
      border: 1px solid #032E74;
    }
  }

  // 二级菜单
  .info-sec {
    display: none;
    width: 540px;
    height: 540px;
    border-radius: 50%;
    clip-path: polygon(50% 50%, 0% 42%, 0% 51%);
    background: linear-gradient(160deg, rgba(3, 46, 116, 0) 0%, #032E74 22%, rgba(3, 46, 116, 0.99) 52%, #032E74 80%, rgba(3, 46, 116, 0) 100%);
    position: absolute;
    top: -110px;
    right: -110px;
    z-index: 0;
    animation: show 0.5s;

    .citem {
      display: flex;
      // justify-content: center;
      align-items: center;
      font-size: 14px;
      color: var(--gdky-second-content-color);
      padding-right: 112px;
      margin-bottom: 16px;
      cursor: pointer;
      position: absolute;
      left: 20%;
      /* 居中 */
      top: 47%;
      /* 居中 */
      transform: translate(-50%, -50%);
      // /* 居中 */
      transform-origin: center right;

      &:hover {
        color: #3C74CF;
      }

      &.active {
        font-weight: 600;
        color: #3C74CF;
      }
    }
  }
   // 一级菜单和二级菜单中间的背景 
  .info-sec-bg {
    display: none;
    width: 340px;
    height: 340px;
    border-radius: 50%;
    background: var(--gdky-layout-bg);
    position: absolute;
    top: -10px;
    right: -10px;
    z-index: 1;
    animation: show 0.5s;
  }

  .close-animation {
    animation: close 0.5s;
  }

  @keyframes show {
    0% {
      transform: rotate(120deg) scale(0);
    }

    100% {
      transform: rotate(0deg) scale(1);
    }
  }

  @keyframes close {
    0% {
      transform: rotate(0deg) scale(1);
    }

    100% {
      transform: rotate(120deg) scale(0);
    }
  }

}
</style>

 index.vue引用菜单组件 IntelligentAnalysis.vue

<template>
  <div class="page--wrap">
    
    <!-- 菜单。右上 -->
    <div class="right-intel-analysis">
      
      <div class="center" @click="handleMenu">
        <!-- 可以放一个图形进来 -->
        <!-- <div class="robot"></div> -->
      </div>
      <transition name="menu">
        <IntelligentAnalysis class="menu" :showMenu="showMenu" v-show="showMenu" @getCurMenu="getCurMenu" />
      </transition>
      
    </div>
    
    

  </div>
</template>

<script>
import { defineComponent, reactive, toRefs, computed, onMounted, provide, ref, watch, getCurrentInstance } from "vue";
import Map from './MapComponents/Map.vue'
import { useAppStore } from '@/store/modules/app'
import { useStore } from '@/store/modules/Supervision/index'
import { GetApiData } from '@/api/Supervision/index.js'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'

import IntelligentAnalysis from './Components/IntelligentAnalysis.vue'

export default defineComponent({
  name: '470543',
  components: {
    IntelligentAnalysis,
  },
  setup() {
    const vm = getCurrentInstance();
    const appStore = useAppStore()
    const modulesStore = useStore()
    const router = useRouter()
    const state = reactive({
      showMenu: false,
      curMeu: {}, // 当前选中的菜单
    });

    onMounted(() => {
    })



    const methods = {
      // 点击右上角菜单
      handleMenu() {
        state.showMenu = !state.showMenu
        if (!state.showMenu) {
          state.curMeu = '' // 清空选中的菜单
        }
      },
      // 获取当前选中的菜单
      getCurMenu(item) {
        state.curMeu = item
      }
    }

    

    return {
      ...toRefs(state),
      ...methods,
    };
  }
});
</script>

<style lang="less" scoped>
.page--wrap {
  position: relative;
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: row;

  .right-intel-analysis {
    .center {
      width: 60px;
      height: 60px;
      background: var(--gdky-overlay-bg);
      border-radius: 50%;
      position: absolute;
      top: 2%;
      right: 1%;
      cursor: pointer;
      z-index: 100;
      display: flex;
      align-items: center;
      justify-content: center;
      .robot {
        // z-index: 5;
        width: 35px;    // 200* 5000    25帧
        height: 35px;
        background-image: url(./assets/analysis-robot.png);
        background-repeat:no-repeat;
        background-position:0 0;
        background-size: 35px 875px;
        animation: robot-dy 2s steps(25) infinite;
      }
      
      @keyframes robot-dy{  
        0%{ background-position:0 0;}  
        100%{ background-position: 0 -875px;}
      }
    }
  
    .menu {
      position: absolute;
      right: -110px;
      top: -110px;
    }
    .menu-enter-active, .menu-leave-active {
      transition: transform 0.5s;
    }
    .menu-enter, .menu-leave-to {
      transform: scale(0);
    }
  } 
}
</style>

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现一个 CSS 扇形菜单,可以按照以下步骤进行: 1. 创建一个带有多个子元素的容器元素,每个子元素代表一个菜单项。 2. 使用 CSS 将容器元素设置为圆形。 3. 将每个菜单项的位置使用 CSS 进行定位,使它们沿着圆形排列。 4. 将每个菜单项使用 CSS 进行旋转,使它们朝向圆心,形成扇形效果。 5. 鼠标悬停在菜单项上时,使用 CSS 进行缩放或者其他效果,以提高交互体验。 下面是一个简单的示例代码,实现了一个包含四个菜单项的扇形菜单: ``` <div class="menu"> <div class="item item-1"></div> <div class="item item-2"></div> <div class="item item-3"></div> <div class="item item-4"></div> </div> <style> .menu { width: 200px; height: 200px; border-radius: 50%; position: relative; } .item { width: 50px; height: 50px; border-radius: 50%; background-color: #ccc; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } .item-1 { transform: rotate(0deg) translate(100px) rotate(0deg); } .item-2 { transform: rotate(90deg) translate(100px) rotate(-90deg); } .item-3 { transform: rotate(180deg) translate(100px) rotate(180deg); } .item-4 { transform: rotate(270deg) translate(100px) rotate(90deg); } .item:hover { transform: scale(1.2); } </style> ``` 在这个示例中,我们使用了绝对定位和 transform 属性来实现菜单项的位置和旋转。同时,使用了 hover 伪类来实现鼠标悬停时的效果。你可以根据自己的需求进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值