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%)); }
  }
}
相关推荐
我叫黑大帅37 分钟前
什么叫可迭代对象?为什么要用它?
前端·后端·python
PineappleCoder40 分钟前
pnpm 凭啥吊打 npm/Yarn?前端包管理的 “硬链接魔法”,破解三大痛点
前端·javascript·前端工程化
fruge1 小时前
前端文档自动化:用 VitePress 搭建团队技术文档(含自动部署)
运维·前端·自动化
yby15411 小时前
【人类写的】anki卡片制作入门
css
CoolerWu1 小时前
TRAE SOLO实战成功展示&总结:一个所见即所得的笔记软体
前端·javascript
Cassie燁2 小时前
el-button源码解读1——为什么组件最外层套的是Vue内置组件Component
前端·vue.js
vx_bscxy3222 小时前
告别毕设焦虑!Python 爬虫 + Java 系统 + 数据大屏,含详细开发文档 基于web的图书管理系统74010 (上万套实战教程,赠送源码)
java·前端·课程设计
北极糊的狐2 小时前
Vue3 子组件修改父组件传递的对象并同步的方法汇总
前端·javascript·vue.js
spionbo2 小时前
Vue3 前端分页功能实现的技术方案及应用实例解析
前端