You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue中点击TabBox组件添加样式并清除其他组件选中样式的实现

解决Vue TabBox组件单选选中样式问题

看起来你现在的问题是每个TabBox子组件自己管理选中状态,导致点击多个时都会保持选中样式对吧?这是因为子组件的状态是独立的,我们需要把选中状态的控制权提升到父组件来统一管理,这样就能实现点击一个选中、其他自动取消的效果。下面是具体的修改方案:

第一步:重构TabBox子组件

子组件不再自己维护选中状态,而是通过props接收父组件传递的激活状态,用计算属性动态处理样式:

<template>
  <div :class="tabStyle" :style="boxstyle" @click="tabClick(name)">
    {{name}}
    <div class="selected-icon" v-show="isActive"></div>
    <div class="tick" v-show="isActive"></div>
  </div>
</template>
<script>
export default {
  name: "tabbox",
  props: {
    name: {
      type: String,
      default: ""
    },
    boxstyle: {
      type: Object,
      default: {} // 修正原代码中的拼写错误:defalult → default
    },
    // 新增props:接收父组件传递的是否激活状态
    isActive: {
      type: Boolean,
      default: false
    }
  },
  // 用计算属性替代原data中的样式状态,自动跟随isActive变化
  computed: {
    tabStyle() {
      return {
        "selected-box": this.isActive,
        "unselected-box": !this.isActive
      };
    }
  },
  methods: {
    tabClick(name) {
      // 点击时仅通知父组件选中的tab名称,不再自行修改状态
      this.$emit("getTabName", name);
    }
    // 删除原borderChange方法,样式逻辑已转移到computed中
  }
};
</script>
<style lang="scss" scoped>
.tab-box {
  display: inline-block;
  position: relative;
  text-align: center;
  padding: 1%;
  font-size: 1rem;
  width: 20%;
}
.unselected-box {
  border: solid 1px #b9a7a76b;
  @extend .tab-box;
}
.selected-box {
  border: solid 1px #5ddb14;
  @extend .tab-box;
}
.selected-icon {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 0;
  height: 0;
  border-color: #5ddb14 transparent;
  border-width: 0 0 20px 25px;
  border-style: solid;
}
.tick {
  position: absolute;
  right: 0;
  bottom: 0;
  color: #fff;
  &::after {
    content: "✓"; // 修正原代码中的乱码内容
  }
}
</style>

第二步:修改父组件,统一管理选中状态

父组件需要维护当前选中的tab名称,将状态传递给每个子组件,实现单选逻辑:

<template>
  <div class="select-tab" :style="tabStyle">
    <Header></Header>
    <div class="label-content" v-for="(item, index) in categories" :key="index">
      <meaning-label :name="item.name"></meaning-label>
      <div class="box-content">
        <!-- 渲染TabBox时,传递isActive属性判断是否选中 -->
        <TabBox 
          @getTabName="getTabName" 
          :name="_item.name" 
          :boxstyle="styles" 
          :isActive="_item.name === currentSelectedTab"
          v-for="(_item, itemIndex) in item.tabs"
          :key="itemIndex"
        ></TabBox>
      </div>
    </div>
  </div>
</template>
<script>
import TabBox from './TabBox.vue';
import Header from './Header.vue';
import MeaningLabel from './MeaningLabel.vue';

export default {
  components: {
    TabBox,
    Header,
    MeaningLabel
  },
  data() {
    return {
      categories: [], // 替换为你的实际分类数据
      styles: {}, // 替换为你的实际box样式数据
      currentSelectedTab: '' // 维护当前选中的tab名称
    };
  },
  methods: {
    getTabName(selectedName) {
      // 子组件点击时,更新当前选中的tab名称
      this.currentSelectedTab = selectedName;
    }
  },
  // 可选:默认选中第一个tab
  mounted() {
    if (this.categories.length > 0 && this.categories[0].tabs.length > 0) {
      this.currentSelectedTab = this.categories[0].tabs[0].name;
    }
  }
};
</script>

方案原理说明

  • 状态提升:将单选状态从子组件移到父组件,让父组件作为唯一的状态管理者,确保同一时间只有一个TabBox处于选中状态。
  • 单向数据流:子组件的选中状态由父组件通过props传递,子组件仅负责触发事件通知父组件,符合Vue的单向数据流原则,代码更易维护和调试。
  • 计算属性:子组件用computed动态计算样式,只要isActive变化,样式会自动更新,无需手动调用方法修改。

内容的提问来源于stack exchange,提问作者index

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:05:07