css扇形菜单动画效果

news2025/1/17 0:27:49

 菜单组件 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>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1685496.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win11安装MySQL

目录[-] 1. 1. 下载2. 2. 安装 参考文档&#xff1a;MySQL :: MySQL 8.4 Reference Manual 1. 下载 mysql官网下载msi安装程序&#xff1a;MySQL :: Begin Your Download 2. 安装 运行下载的mis程序,逐步安装。 安装模式&#xff1a; complete; 进入配置&#xff1a; data di…

声明式管理方法

一.方法 1.适合于对资源的修改操作 2.声明式资源管理方法依赖于资源配置清单文件对资源进行管理 资源配置清单文件有两种格式&#xff1a;yaml&#xff08;人性化&#xff0c;易读&#xff09;&#xff0c;json&#xff08;易于api接口解析&#xff09; 3.对资源的管理&#x…

第06章 数据加载、存储与文件格式

以下内容参考自https://github.com/iamseancheney/python_for_data_analysis_2nd_chinese_version/blob/master/%E7%AC%AC05%E7%AB%A0%20pandas%E5%85%A5%E9%97%A8.md 《利用Python进行数据分析第2版》 用以学习和记录。 输入输出通常可以划分为几个大类&#xff1a;读取文本文…

代码随想录--哈希表--有效的字母异位词

题目 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 示例 1: 输入: s “anagram”, t “nagaram” 输出: true 示例 2: 输入: s “rat”, t “car” 输出: false 说明: 你可以假设字符串只包含小写字母。 思路 先看暴力的解法&am…

Github 2024-05-23 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-05-23统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目3TypeScript项目2非开发语言项目1Java项目1Shell项目1Jupyter Notebook项目1JavaScript项目1Java设计模式:提高开发效率的正规化实践…

适合企业的通配符https证书

通配符https证书&#xff0c;也被称为泛域名https证书&#xff0c;是一种可以保护主域名及其所有子域名的数字证书产品。通配符https证书由证书颁发机构(CA)签发&#xff0c;为http明文传输协议加上安全套接层&#xff0c;加密客户端与服务器之间传输的信息&#xff0c;为网站访…

Java方法的递归

Java方法的递归 前言一、递归的概念示例代码示例 二、递归执行过程分析代码示例执行过程图 三、递归练习代码示例按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)递归求 1 2 3 ... 10写一个递归方法&#xff0c;输入一个非负整数&#xff0c;返回组成它的数字之和. …

stm32学习-光敏传感器控制蜂鸣器

接线 GPIO配置 初始化GPIO 1.使用RCC开启GPIO时钟 void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); 作用&#xff1a;外设时钟控制(根据外设连接的总线选择要开启的时钟&#xff09; RCC_AHBPeriph/RCC_APB2Periph/RCC_APB1Periph&#x…

基于EifficientNet的视网膜病变识别

分析一下代码 model.py ①下面这个方法的作用是&#xff1a;将传入的ch&#xff08;channel&#xff09;的个数调整到离它最近的8的整数倍&#xff0c;这样做的目的是对硬件更加友好。 def _make_divisible(ch, divisor8, min_chNone):if min_ch is None:min_ch divisornew…

学习Uni-app开发小程序Day23

今天学习了将上一章的所有核算的js&#xff0c;抽离出去&#xff0c;让在其他地方可以直接调用&#xff0c;然后和适配抖音的办法&#xff0c;封装网络请求&#xff1b; 抽离公共方法 如何将公共方法抽离&#xff1f; 1、在根目录创建一个目录&#xff0c;一般起名是:utils 2…

谷歌快速收录怎么做?

快速收录顾名思义&#xff0c;就是让新的的网页内容能够迅速被谷歌搜索引擎抓取、索引和显示在搜索结果中&#xff0c;这对于做seo来说非常重要&#xff0c;因为它有助于新发布的内容尽快出现在谷歌的搜索结果中&#xff0c;从而增加网站的流量 想做谷歌快速收录谷歌推荐了几种…

告别硬编码:Spring条件注解优雅应对多类场景

一、背景 在当今的软件开发中&#xff0c;服务接口通常需要对应多个实现类&#xff0c;以满足不同的需求和场景。举例来说&#xff0c;假设我们是一家2B公司&#xff0c;公司的产品具备对象存储服务的能力。然而&#xff0c;在不同的合作机构部署时&#xff0c;发现每家公司底…

每天五分钟深度学习框架PyTorch:创建具有特殊值的tensor张量

本文重点 tensor张量是一个多维数组,本节课程我们将学习一些pytorch中已经封装好的方法,使用这些方法我们可以快速创建出具有特殊意义的tensor张量。 创建一个值为空的张量 import torch import numpy as np a=torch.empty(1) print(a) print(a.dim()) print(s.shape) 如图…

python3如何查看是32位还是64位

在安装一些python的软件包时&#xff0c;经常安装错误&#xff0c;可能是跟python的位数有关系。 下面告诉大家如何查看python的位数。 第一种方法&#xff1a;通过在cmd中输入“python”即可。 第二种方法&#xff1a;通过platform包查看&#xff0c;首先导入platform包&…

Nginx企业级负载均衡:技术详解系列(11)—— 实战一机多站部署技巧

你好&#xff0c;我是赵兴晨&#xff0c;97年文科程序员。 工作中你是否遇到过这种情况&#xff1a;公司业务拓展&#xff0c;新增一个域名&#xff0c;但服务器资源有限&#xff0c;只能跟原有的网站共用同一台Nginx服务器。 也就是说两个网站的域名都指向同一台Nginx服务器…

金融信贷风控基础知识

一、所谓风控(What && Why) 所谓风控&#xff0c;可以拆解从2个方面看&#xff0c;即 风险和控制 风险(what) 风险 这里狭隘的特指互联网产品中存在的风险点&#xff0c;例如 账户风险 垃圾注册账号账号被泄露盗用 交易支付风险 刷单&#xff1a;为提升卖家店铺人气…

小程序-滚动触底-页面列表数据无限加载

// index/index.vue <template> <!-- 自定义导航栏 --> <CustomNavbar /> <scroll-view scrolltolower"onScrolltolower" scroll-y class"scroll-view"> <!-- 猜你喜欢 --> <Guess ref"guessRef" /> </s…

利用Python队列生产者消费者模式构建高效爬虫

目录 一、引言 二、生产者消费者模式概述 三、Python中的队列实现 四、生产者消费者模式在爬虫中的应用 五、实例分析 生产者类&#xff08;Producer&#xff09; 消费者类&#xff08;Consumer&#xff09; 主程序 六、总结 一、引言 随着互联网的发展&#xff0c;信…

利用Anaconda+Pycharm配置PyTorch完整过程

说在前面&#xff1a;这篇是记录贴&#xff0c;因为被配置环境折磨了大半天&#xff0c;所以记录下来下次方便配置&#xff0c;有点像流水账&#xff0c;有不懂的地方可以评论问。 参考文章&#xff1a; https://blog.csdn.net/m0_48609250/article/details/129402319 环境&…

Android:使用Kotlin搭建MVC架构模式

一、简介Android MVC架构模式 M 层 model &#xff0c;负责处理数据&#xff0c;例如网络请求、数据变化 V 层 对应的是布局 C 层 Controller&#xff0c; 对应的是Activity&#xff0c;处理业务逻辑&#xff0c;包含V层的事情&#xff0c;还会做其他的事情&#xff0c;导致 ac…