Vue3 + Less 实现动态圆角 TabBar:从代码到优化实践

在前端开发中,TabBar 是一个非常常见的 UI 组件,而在一些设计需求中,我们希望激活的 Tab 有动态变化的圆角效果,并且宽度可以根据选中状态自适应。本文将分享一个 Vue3 + Less 实现的 TabBar 组件案例,完整分析代码结构、实现思路,并展示优化技巧。

效果预览:

🧩 需求分析

我们希望 TabBar 拥有以下特性:

  1. 动态激活状态 :根据 modelValue 高亮当前 Tab。
  2. 圆角过渡效果:激活 Tab 的上下圆角动态显示。
  3. 自适应宽度:选中 Tab 宽度放大,未选中 Tab 等分。
  4. 复用性强:多种激活形态(左圆角、右圆角、左右圆角)可复用样式。
  5. 响应用户点击:选中状态更新并触发事件。

🛠 组件实现

1️⃣ 模板部分

vue 复制代码
<template>
  <div class="tabbar" :style="{ 'grid-template-columns': getGridFr }">
    <div
      v-for="(it) in tabs"
      :key="it.value"
      :class="{
        'tabbar-item': true,
        'active': modelValue === it.value && modelValue === 'use',
        'active1': modelValue === it.value && modelValue === 'charge',
        'active2': modelValue === it.value && modelValue === 'code',
      }"
      @click="select(it.value)"
    >
      <div class="top"></div>
      {{ it.label }}
    </div>
  </div>
</template>
  • 动态类绑定 :根据不同 Tab 值,使用 active1/active2/active3 控制圆角样式。
  • 网格布局grid-template-columns 根据选中状态动态调整宽度。

样式部分(Less )

less 复制代码
.tabbar {
  display: grid;
  transition: all 0.3s;
  --th: 8px;

  &-item {
    text-align: center;
    height: 40px;
    background-color: var(--el-color-primary);
    color: #fff;
    font-size: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    user-select: none;
  }

  // ----------- 公共激活样式 -----------
  .active-base() {
    color: var(--el-color-primary);
    background-color: #fff;
    position: relative;
    --bh: 40px;

    .top {
      position: absolute;
      height: var(--th);
      background-color: #fff;
      top: calc(var(--th) * -1);
    }
  }

  // 圆角片段(左右通用)
  .circle(@pos, @clip) {
    display: block;
    content: '';
    position: absolute;
    width: var(--bh);
    height: var(--bh);
    background-color: var(--el-color-primary);
    @{pos}: 0;
    bottom: 0;
    z-index: 1;
    clip-path: @clip;
  }

  // ----------- 各种激活样式 -----------

  // 左右都有圆角
  .active {
    .active-base();

    .top {
      border-radius: 100px 100px 20px 20px;
      width: calc(100% - 80px);
    }

    &::before { .circle(left, ellipse(100% 100% at 0% 0%)); }
    &::after  { .circle(right, ellipse(100% 100% at 100% 0%)); }
  }

  // 右侧圆角
  .active1 {
    .active-base();

    .top {
      border-radius: 0 100px 20px 20px;
      width: calc(100% - 40px);
      left: 0;
    }

    &::after { .circle(right, ellipse(100% 100% at 100% 0%)); }
  }

  // 左侧圆角
  .active2 {
    .active-base();

    .top {
      border-radius: 100px 0 20px 20px;
      width: calc(100% - 40px);
      right: 0;
    }

    &::before { .circle(left, ellipse(100% 100% at 0% 0%)); }
  }
}
相关推荐
大家的林语冰29 分钟前
CSS 已死?DOM 性能黑洞!Pretext 排版革命让你在文本间跳舞,没有 DOM 也能纵享丝滑~
前端·javascript·css
vipbic39 分钟前
我也该升级了,陪伴了我7年的博客
前端
Lee川1 小时前
RAG 实战:从一篇掘金文章出发,拆解检索增强生成的全链路
前端·人工智能·后端
Lee川1 小时前
MCP 高德地图实战:当 AI 学会使用工具,一个协议如何重塑大模型的行动边界
前端·人工智能·后端
ZC跨境爬虫1 小时前
跟着 MDN 学CSS day_14:(尺寸调整技能测试与实战解析)
前端·css·ui·html·tensorflow
kyriewen2 小时前
用魔法打败魔法:我让AI替我去面试前端岗,AI面试官给我打了92分,还发了offer
前端·javascript·面试
IT_陈寒2 小时前
Redis批量删除踩了坑,原来DEL命令不是万能的
前端·人工智能·后端
lichenyang4532 小时前
鸿蒙聊天 Demo 练习 06:AI 思考气泡与 MVVM + Controller 结构重构
前端
Lkstar2 小时前
Vue keep-alive 原理全解:LRU 缓存策略、源码级理解
前端·vue.js·面试
会联营的陆逊2 小时前
html2canvas 1.4.1 在 iOS Safari 中生成图片卡住的问题排查与修复
前端