vue3 弧形菜单构思设计

15 篇文章 0 订阅

 1 思路

  • 菜单列表纵向排列,每一项菜单文字根据背景进行旋转
  • 菜单跳转时,整体旋转

 2 代码

因为曲线扁平,所以下面style中用每一项文字旋转和右边距仅仅进行了视觉上拟合,并没有进行严谨的拟合,参数可以自行修改

<template>
  <img class="menu-icon" src="@/assets/image/menu.png" @click="handleMenuStatus" />
  <div class="menu-wapper" :class="{ hidden: hideMenu }">
    <div
      class="menu-list"
      :style="{ transformOrigin: '-1100px 50%', transform: `rotate(${angle}deg)` }"
    >
      <div
        v-for="(item, index) in menuList"
        :key="item.id"
        class="menu-item"
        :class="{ active: baseIndex === index }"
        :style="{
          transform: `rotate(${(index + 1 - Math.ceil(menuList.length / 2)) * 3}deg)`,
          marginRight: `${
            Math.pow(Math.abs(index + 1 - Math.ceil(menuList.length / 2)), 2) * 1.55
          }px`,
        }"
        @click="handleSwitchMenu(item)"
      >
        <span class="menu-text"> {{ item.name }}</span>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
const router = useRouter();
const route = useRoute();

const menuList = ref([
  {
    id: 1,
    name: '平台管理',
    path: '/menu1',
  },
  {
    id: 2,
    name: '人员管理',
    path: '/menu2',
  },
  {
    id: 3,
    name: '信息管理',
    path: '/menu3',
  },
  {
    id: 4,
    name: '菜单管理',
    path: '/menu4',
  },
  {
    id: 5,
    name: '权限管理',
    path: '/menu5',
  },
  {
    id: 6,
    name: '资产管理',
    path: '/menu6',
  },
  {
    id: 7,
    name: '系统管理',
    path: '/menu7',
  },
]);
const angle = ref(0);
const curMenu = ref();
const hideMenu = ref(false);
const baseIndex = ref(Math.floor(menuList.value.length / 2));

onMounted(async () => {
  curMenu.value = menuList.value.find(item => item.path === route.path);
  handleSwitchMenu(curMenu.value);
});

const handleMenuStatus = () => {
  hideMenu.value = !hideMenu.value;
};

const handleSwitchMenu = async (menu: any) => {
  const selectedIndex = menuList.value.findIndex(item => item.id === menu.id);
  angle.value += -(selectedIndex - baseIndex.value) * 2.75;
  baseIndex.value = selectedIndex;
  router.push({
    path: menu.path,
  });
};
</script>
<style lang="scss" scoped>
.menu-icon {
  position: fixed;
  z-index: 600;
  left: 0.5%;
  top: 50%;
  cursor: pointer;
  width: 20px;
  height: 20px;
}

.menu-wapper {
  position: fixed;
  left: 0;
  bottom: 5%;
  width: 240px;
  height: 80%;
  background: url('@/assets/image/outline.png') center no-repeat;
  background-size: 80% 100%;
  z-index: 200;
  transition: all 0.5s ease-in-out;
  transform-origin: -1100px 50%;

  &.hidden {
    transform-origin: -1100px 50%;
    transform: rotate(-60deg);
    opacity: 0;

    &:hover {
      transform: rotate(0deg);
      opacity: 1;
    }
  }

  .menu-list {
    width: 100%;
    height: 100%;
    padding-right: 48px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-end;
    transition: all 0.5s ease-in-out;

    .menu-item {
      height: 35px;
      width: 100px;
      margin-top: 20px;
      font-size: 20px;
      display: flex;
      justify-content: center;
      align-items: center;
      cursor: pointer;

      &.active {
        border-radius: 20px;
        border: 2px solid #f3da94;
        &:before {
          content: '';
          width: 4px;
          height: 4px;
          position: absolute;
          top: 40%;
          left: -10px;
          background-color: #f3da94;
          border-radius: 50%;
        }
        &:after {
          content: '';
          width: 4px;
          height: 4px;
          position: absolute;
          top: 40%;
          right: -10px;
          background-color: #f3da94;
          border-radius: 50%;
        }
        .menu-text {
          font-weight: bold;
        }
      }

      .menu-text {
        color: #d7e4f1;
      }
    }
  }
}
</style>

3 效果

4 改进

为了使得选中菜单并与菜单icon在一条水平线上,可以进行如下方法改进:

  1. 获取背景曲线的半径(假设是圆周的一部分),改变transform-origin参数,计算菜单选中时需要偏转的度数
  2. 直接以贝塞尔三次曲线拟合背景曲线,修改相关参数

 

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值