美文网首页
Vue 撸一个半环形菜单

Vue 撸一个半环形菜单

作者: almj | 来源:发表于2020-10-27 11:09 被阅读0次

    需求描述:

    实现一个环形菜单、一半隐藏、一半滚动展示,有点像摩天轮,每一个小环球代表一个菜单,被选中的菜单处于激活状态,并在屏幕上显示此菜单对应的功能说明。

    实现效果

    QQ图片20201027110150.png

    实现思路

    计算一个方框区域,以此方框边长一半作为半径画个圆,并按照菜单个数均分菜单将菜单分不到圆环上面话小球,用css控制其激活、hover状态,监听小球点击事件,并更新左边的菜单说明。

    代码实现

    组件代码 CircleMenue.vue

    <template>
      <div class="overall">
        <div class="description">
          <h1 class="desc-title">{{ descTitle }}</h1>
          <div class="desc-content">
            <span>{{ descContent }}</span>
          </div>
        </div>
        <div class="circle-box">
          <div class="circle" :style="`width:${circle_w}px;height:${circle_h}px`">
            <div
              class="origin"
              :style="`width:${box_w}px;height:${box_h}px;transform: rotate(${stard}deg);`"
            >
              <div
                :style="`width:${box_w}px;height:${box_h}px;transform: rotate(${-stard}deg);`"
                class="img-box"
                v-for="(item, index) in menus"
                :key="index"
                @click="Turn(index)"
              >
                <div class="box">
                  <div class="content">{{ item.name }}</div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      props: ["menus"], //菜单数据
      data() {
        return {
          circle_w: window.innerHeight, //圆盘的宽
          circle_h: window.innerHeight, //圆盘的高
          box_w: 300, //圆盘上覆盖的小圆点宽
          box_h: 300, //圆盘上覆盖的小圆点高
          PI: 200, //分布角度,默认为360deg
          stard: 90, //起始角度
          stard_s: null, //用来默认储存第一个初始值
          boxNum: 6, //圆盘上覆盖的小圆点个数
          descTitle: "", //模块描述标题
          descContent: "", //模块描述内容
          activeIndex: 0, //默认下标
        };
      },
      created() {
        this.stard_s = this.stard;
      },
    
      mounted() {
        this.init();
        this.Turn(this.activeIndex);
      },
      methods: {
        //初始化小圆点,根据计算使其分布到对应位置
        init() {
          let box = document.querySelectorAll(".img-box");
          let avd = this.PI / box.length; //每一个 img-box 对应的角度
          let ahd = (avd * Math.PI) / 180; //每一个 img-box 对应的弧度
          let radius = this.circle_w / 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";
          }
        },
        //点击相对应小圆点,圆盘进行相对应角度的转动
        Turn(index) {
          let _this = this;
          let bx = document.querySelectorAll(".box");
          _this.stard = index * (_this.PI / _this.menus.length) + _this.stard_s;
          for (let i = 0; i < bx.length; i++) {
            if (i == index) {
              bx[i].classList.add("box-active");
            } else {
              bx[i].classList.remove("box-active");
            }
          }
          this.setDescription(index);
        },
    
        setDescription(index) {
          this.descTitle = this.menus[index].name;
          this.descContent = this.menus[index].desc;
        },
      },
    };
    </script>
    
    <style lang="scss" scoped>
    .overall {
      width: 100%;
      height: 90%;
      top: 5%;
      position: absolute;
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      background: #5c6070;
    }
    .description {
      background-color: rgba(119, 137, 125, 0.4);
      width: 60%;
      position: absolute;
      padding: 10px 20px;
      left: 0;
      top: 32%;
      height: 220px;
      z-index: 9999;
      box-shadow: 0 0 10px rgb(0, 0, 0);
      border: 1px solid green;
    
      .desc-title {
        height: 20%;
        font-size: 32px;
        font-weight: bold;
        text-align: center;
        color: white;
      }
      .desc-content {
        font-size: 18px;
        display: table;
        color: white;
        width: 80%;
        height: 55%;
        margin: auto;
      }
      .desc-content span {
        display: table-cell;
        vertical-align: middle;
        text-indent: 5%;
        line-height: 30px;
      }
    }
    
    .circle-box {
      position: absolute; //注释--------------------------此处显示全圆
      overflow: hidden; //注释----------------------此处显示全圆
      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-left: 50%; //注释----------------此处显示全圆
        .origin {
          position: relative;
          transition: 0.5s; //控制圆盘的的旋转速率
          .img-box {
            user-select: none;
            position: absolute;
            top: 0;
            left: 0;
            transition: none !important;
            pointer-events: none;
            .box {
              pointer-events: all !important;
              width: 100%;
              height: 100%;
              transition: 0.3s;
              display: flex;
              justify-content: center;
              align-items: center;
              position: absolute;
              left: 0;
              top: 0;
              border-radius: 50%;
              transform: scale(0.1);
              cursor: pointer;
              color: white;
              font-size: 40px;
              background: #00b3c7;
              overflow: hidden;
              &:hover {
                transform: scale(0.3);
              }
              &:hover .content {
                opacity: 1;
                background: #00b3c7 !important;
                color: white;
              }
              .content {
                width: 100%;
                height: 100%;
                display: flex;
                align-items: center;
                justify-content: center;
                opacity: 0;
              }
            }
            .box-active {
              transition-delay: 0.5s;
              border: 5px solid white;
              transform: scale(1) !important;
              .box::before {
                content: "";
                position: absolute;
                top: -2px;
                left: -2px;
                right: -2px;
                bottom: -2px;
                background: #ffffff;
                z-index: -1; /*元素堆叠顺序*/
              }
              /*另一个溢出的盒子,模糊形成光晕效果*/
              .box::after {
                content: "";
                position: absolute;
                top: -2px;
                left: -2px;
                right: -2px;
                bottom: -2px;
                background: #ffffff;
                z-index: -2;
                /*添加模糊滤镜*/
                filter: blur(40px);
              }
              .box::before,
              .box::after {
                /*三色渐变,中间为背景色,融入背景*/
                background: linear-gradient(235deg, #89ff00, #060c21, #00bcd4);
              }
    
              .content {
                opacity: 1;
                font-size: 30px;
                box-sizing: border-box;
                background: #00b3c7 !important;
                color: white;
                text-align: center;
              }
            }
          }
        }
      }
    }
    </style>
    

    组件调用

    <template>
      <div id="app">
        <CircleMenu :menus="menus" />
      </div>
    </template>
    
    <script>
    import CircleMenu from "./components/circleMenu";
    
    export default {
      name: "App",
      components: {
        CircleMenu,
      },
      data() {
        return {
          menus: [
            {
              name: "测试菜单1",
              desc:
                "测试菜单1说明测试菜单1说明测试菜单1说明测试菜单1说明测试菜单1说明测试菜单1说明测试菜单1说明测试菜单1说明测试菜单1说明",
            },
            {
              name: "测试菜单2",
              desc:
                "测试菜单2说明测试菜单2说明测试菜单2说明测试菜单2说明测试菜单2说明测试菜单2说明",
            },
            {
              name: "测试菜单3",
              desc: "测试菜单3说明",
            },
            {
              name: "测试菜单4",
              desc: "测试菜单4说明测试菜单4说明测试菜单4说明",
            },
            { 
               name: "测试菜单5", 
               desc: "测试菜单5说明说明" },
            {
              name: "测试菜单6",
              desc: "测试菜单啦啦啦啦",
            },
            { 
              name: "测试菜单7", 
              desc: "测试菜单7说明" },
          ],
        };
      },
    };
    </script>
    
    <style>
    #app {
      height: 100%;
      margin: 0px;
      padding: 0px;
      font-family: "Avenir", Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      overflow: hidden;
      background-color: #5c6070;
    }
    </style>
    
    

    完毕!

    相关文章

      网友评论

          本文标题:Vue 撸一个半环形菜单

          本文链接:https://www.haomeiwen.com/subject/kkitvktx.html