vue实现弧形菜单栏

需求: 实现一个弧形的菜单栏,并将激活的菜单项移动到中间位置,点击按钮可对该菜单栏进行显示隐藏。

1. 实现效果

菜单显示

菜单隐藏

2. 实现原理

按照圆环弧度计算每个菜单项应该分布的位置并进行设置,在点击菜单项时更新菜单的起始角度,重新进行分布。

3. 实现代码

<template>
<div class="circle-menu-box">
  <span v-if="showMenu" class="iconfont iconarrow-left" @click="onHiddenMenu"></span>
  <span v-else class="iconfont iconarrow-right" @click="onShowMenu"></span>
  <div class="circle" :style="`width:${circleInfo.circle_w}px;height:${circleInfo.circle_h}px`">
    <div
    class="origin"
    :style="`width:${circleInfo.box_w}px;transform: rotate(${circleInfo.stard}deg);visibility: ${showMenu ? 'visible':'hidden'}`"
    >
      <div
          :style="`width:${circleInfo.box_w}px;transform: rotate(${-circleInfo.stard}deg);`"
          class="img-box"
          v-for="(item, index) in menus"
          :key="index"
          @click="Turn(index)"
        >
          <div :class="['circle-content-box', circleInfo.activeIndex === index ? 'box-active':'']">
              <div class="content">{{ item.name }}</div>
          </div>
        </div>
      </div>
    </div>
</div>
  
</template>
    
<script setup>
import {reactive,ref, onMounted, nextTick} from 'vue'

let showMenu = ref(true) // 是否显示菜单
let menus = reactive([ // 菜单项
        { name: '菜单一'},
        { name: '菜单二'},
        { name: '菜单三'},
        { name: '菜单四'},
        { name: '菜单五'},
        { name: '菜单六'},
        { name: '菜单七'},
        { name: '菜单八'},
        { name: '菜单九'},
        { name: '菜单十'},
        { name: '菜单十一'},
      ])
let circleInfo = reactive({ // 圆形框架的数据
    circle_w: 1300, //圆盘的宽
    circle_h: 1300, //圆盘的高
    box_w: 300, //圆盘上覆盖的小圆点宽
    PI: 90, //分布角度,默认为360deg
    stard: -50, //起始角度
    stard_s: -50, //用来默认储存第一个初始值
    boxNum: 10, //圆盘上覆盖的小圆点个数
    descTitle: "", //模块描述标题
    descContent: "", //模块描述内容
    activeIndex: 0, //默认激活项
})

onMounted(() => {
  circleInfo.activeIndex = Math.floor(menus.length / 2) // 默认激活中间项
  init()
  Turn(circleInfo.activeIndex)
})

/**
 * 初始化项目,根据计算使其分布到对应位置
 **/
const init = () => {
    let box = document.querySelectorAll(".img-box");
    let avd = circleInfo.PI / box.length; //每一个 菜单项 对应的角度
    let ahd = (avd * Math.PI) / 180; //每一个 菜单项 对应的弧度
    let radius = (circleInfo.circle_w + 320) / 2; //圆的半径
    for (let i = 0; i < box.length; i++) {  // 给菜单项定位
      box[i].style.left = (Math.sin(ahd * i) * radius) + "px";
      box[i].style.top = (Math.cos(ahd * i) * radius)+ "px";
    }
}

/** 
 * 点击菜单项,圆盘进行相对应角度的转动
 **/
const Turn = (index = 0) => {
    let bx = document.querySelectorAll(".circle-content-box");
    circleInfo.activeIndex = index

    let deg = (10 - index) * 10 // 改变起始角度
    circleInfo.stard = - deg
    nextTick(() => {
      init()
    })
}

/**
 * 隐藏菜单
 */
const onHiddenMenu = () => {
  showMenu.value = false
  let boxDom = document.querySelector('.circle-menu-box')
  boxDom.style.left = '-31%'
}

/**
 * 显示菜单
 */
const onShowMenu = () => {
  showMenu.value = true
  let boxDom = document.querySelector('.circle-menu-box')
  boxDom.style.left = '-28%'
  init()
}

</script>
    
<style lang="scss"  scoped>
.circle-menu-box {
  position: absolute; //注释--------------------------此处显示全圆
  // overflow: hidden; //注释----------------------此处显示全圆
  left: -28%; //注释---------------------此处显示全圆
  top: 50%;
  transform: translateY(-50%);
  transition: 0.5s;

  .iconfont {
    position: absolute;
    top: 50%;
    font-size: 50px;
    transform: translateX(-50%);
    color:  #86E7FF;
    cursor: pointer;
    z-index: 15;
  }

  .iconarrow-left {
    right: 5%;
  }

  .iconarrow-right {
    right: 0;
  }

  .circle {
    // transform: scale(0.9);
    width: 100%;
    height: 90%;
    border-radius: 50%;
    box-sizing: border-box;
    // border: 1px solid #4d4c4c;
    box-shadow: 0 0 8px #DDD;
    -moz-box-shadow: 0 0 8px #DDD;
    -webkit-box-shadow: 0 0 8px #DDD;
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    // margin-right: 50%; //注释----------------此处显示全圆
    background: linear-gradient(90deg, rgba(178, 243, 254, 0) 0%, rgba(178, 243, 254, 0) 0%, rgba(142, 233, 253, 0) 54%,
     rgba(142, 233, 253, 0) 80%, rgba(123, 228, 252, 0.2) 100%);
    border: 4px solid rgba(123, 228, 252, 1);

    .origin {
      position: relative;
      transition: 0.5s; //控制圆盘的的旋转速率
      .img-box {
        position: absolute;
        top: 0;
        left: 0;
        .circle-content-box {
          width: 100%;
          height: 100%;
          cursor: pointer;
          overflow: hidden;
          
          .content {
           font-size: 28px;
            font-family: SourceHanSansCN-Medium, SourceHanSansCN;
            font-weight: 500;
            color: #C6DAED;
          }
        }
        .box-active {

          .content {
           font-size: 38px;
            font-family: SourceHanSansCN-Bold, SourceHanSansCN;
            font-weight: bold;
            color: #7BE4FC;
          }
        }
      }
    }
  }
}
</style>

4. 参考文档

忘了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容