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

如何在v-for循环内为多个元素动态设置类名?

解决v-for循环内动态设置类名的问题

你的问题核心在于当前用的premiumCoverage这类全局变量是共享的,所有循环出来的pet项都会复用同一个状态,导致点击任意一个卡片,所有循环项的样式都会跟着变。要解决这个,得把选中状态和每个pet的索引绑定,让每个pet单独管理自己的选中套餐。

步骤1:重构状态变量

把原来的单个布尔变量(premiumCoverage、standardCoverage等)替换成一个对象,用来存储每个pet对应的选中套餐类型:

// 在组件的data中定义
data() {
  return {
    selectedCoverage: {} // 键为pet的index,值为选中的套餐类型,比如'premium'/'standard'等
  }
}

步骤2:修改模板的类绑定逻辑

把原来的:class="premiumCoverage ? 'active' : 'plans'"这类判断,改成判断当前pet的选中类型是否匹配当前卡片的套餐类型:

比如Premium卡片的类绑定修改为:

:class="selectedCoverage[index] === 'premium' ? 'active' : 'plans'"

对应的按钮类绑定:

:class="selectedCoverage[index] === 'premium' ? 'selected' : 'select-btn'"

按钮文本同步修改:

{{ selectedCoverage[index] === 'premium' ? 'SELECTED' : 'SELECT' }}

其他卡片(Standard、Base、Custom)同理,替换对应的套餐类型字符串即可。

步骤3:更新点击事件处理函数

修改coverageSelected方法,把选中的套餐类型存到对应pet的索引下:

methods: {
  coverageSelected(type, deductible, index) {
    // 给当前pet设置选中的套餐类型,用$set确保Vue能检测到属性变化
    this.$set(this.selectedCoverage, index, type);
    // 这里可以保留你原本处理deductible等逻辑
  }
}

修改后的完整模板示例

<div v-for="(pet,index) in pets" :key="pet.id">
  <v-row class="d-flex justify-center">
    <v-col cols="12" sm="12" md="12" class="d-flex justify-center">
      <v-col cols="3">
        <v-card
          class="pa-2 text-center"
          :class="selectedCoverage[index] === 'premium' ? 'active' : 'plans'"
        >
          <v-card-title class="mb-3 primary--text d-flex justify-center">
            <strong>${{ premiumPrice(0, index).toFixed(2) }}</strong>
          </v-card-title>
          <v-card-subtitle class="primary--text mb-3">
            per month
          </v-card-subtitle>
          <v-card-text>$0 DEDUCTIBLE</v-card-text>
          <v-card-text style="overflow-y: auto; height:150px">
            The best choice for <br>planning for <br>unexpected vet bills.
          </v-card-text>
          <v-btn
            outlined
            class="mb-6 font-weight-bold"
            :class="selectedCoverage[index] === 'premium' ? 'selected' : 'select-btn'"
            @click="coverageSelected('premium', 0, index)"
          >
            {{ selectedCoverage[index] === 'premium' ? 'SELECTED' : 'SELECT' }}
          </v-btn>
        </v-card>
      </v-col>
      <!-- Standard卡片 -->
      <v-col cols="3">
        <v-card
          class="pa-2 text-center"
          :class="selectedCoverage[index] === 'standard' ? 'active' : 'plans'"
        >
          <v-card-title class="mb-3 primary--text d-flex justify-center">
            <strong>${{ standardPrice(200, index).toFixed(2) }}</strong>
          </v-card-title>
          <v-card-subtitle class="primary--text mb-3">
            per month
          </v-card-subtitle>
          <v-card-text>$200 DEDUCTIBLE</v-card-text>
          <v-card-text style="overflow-y: auto; height:150px">
            OUR MOST POPULAR <br>CHOICE
          </v-card-text>
          <v-btn
            outlined
            class="mb-6 font-weight-bold"
            :class="selectedCoverage[index] === 'standard' ? 'selected' : 'select-btn'"
            @click="coverageSelected('standard', 200, index)"
          >
            {{ selectedCoverage[index] === 'standard' ? 'SELECTED' : 'SELECT' }}
          </v-btn>
        </v-card>
      </v-col>
      <!-- Base卡片 -->
      <v-col cols="3">
        <v-card
          class="pa-2 text-center"
          :class="selectedCoverage[index] === 'base' ? 'active' : 'plans'"
        >
          <v-card-title class="mb-3 primary--text d-flex justify-center">
            <strong>${{ basePrice(700, index).toFixed(2) }}</strong>
          </v-card-title>
          <v-card-subtitle class="primary--text mb-3">
            per month
          </v-card-subtitle>
          <v-card-text>$700 DEDUCTIBLE</v-card-text>
          <v-card-text style="overflow-y: auto; height:150px">
            A great choice to help<br>reduce your monthly <br>payment.
          </v-card-text>
          <v-btn
            outlined
            class="mb-6 font-weight-bold"
            :class="selectedCoverage[index] === 'base' ? 'selected' : 'select-btn'"
            @click="coverageSelected('base', 700, index)"
          >
            {{ selectedCoverage[index] === 'base' ? 'SELECTED' : 'SELECT' }}
          </v-btn>
        </v-card>
      </v-col>
      <!-- Custom卡片 -->
      <v-col cols="3">
        <v-card
          class="pa-2 text-center"
          :class="selectedCoverage[index] === 'custom' ? 'active' : 'plans'"
        >
          <v-card-title class="mb-4 primary--text d-flex justify-center">
            <strong>Customize <br>your price</strong>
          </v-card-title>
          <v-card-text>CUSTOM</v-card-text>
          <v-card-text style="min-height:150px">
            Choose a price that <br>works for you! Select <br>this option to <br>customize your <br>deductible.
          </v-card-text>
          <v-btn
            outlined
            class="mb-6 font-weight-bold"
            :class="selectedCoverage[index] === 'custom' ? 'selected' : 'select-btn'"
            @click="coverageSelected('custom', 0, index)"
          >
            {{ selectedCoverage[index] === 'custom' ? 'SELECTED' : 'SELECT' }}
          </v-btn>
        </v-card>
      </v-col>
    </v-col>
  </v-row>
</div>

修改后,每个pet的套餐选中状态完全独立,点击某个pet下的按钮只会改变当前pet对应的卡片和按钮样式,不会影响其他pet项。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 23:24:56