You need to enable JavaScript to run this app. Vue集成Bootstrap4折叠卡片出现重复key警告、联动展开及过渡失效问题
优惠活动
大模型
产品
解决方案
定价
更多

Vue集成Bootstrap4折叠卡片出现重复key警告、联动展开及过渡失效问题

问题根源

  • 重复key警告:你对同一份长度为1的pricing数组执行了3次v-for循环,三次循环生成的key都是0,触发重复key报错
  • 多卡片同步展开:三张卡片绑定的是同一份expand状态,修改任意卡片的状态都会同步到所有卡片
  • 过渡效果失效:同时使用了Bootstrap原生折叠的data-*属性和Vue状态控制show类,两套逻辑冲突导致过渡动画异常
  • 存在语法错误:data配置尾部多了冗余],methods前缺少逗号,多个方法定义之间缺少逗号
  • 重复ID问题:模板中存在大量重复的固定ID,违反HTML ID唯一性规则,会导致DOM操作异常

修复方案

  1. 重构pricing数组结构,每张套餐卡对应数组内一个独立元素,每个元素维护自身的套餐信息、展开状态
  2. 删除冗余的2次v-for循环,仅用一次循环动态渲染所有卡片,避免重复代码和key冲突
  3. 移除Bootstrap原生折叠相关的data-toggle/data-target属性,完全由Vue状态控制展开收起,避免逻辑冲突
  4. 合并三个重复的折叠方法为一个通用方法
  5. 修正JS语法错误,将重复ID改为类名

修复后完整代码

<template>
<div class="prices">
  <div class="container">
    <h1 class="comfortHeader" style="margin-bottom: 50px;">Наши цены</h1>
    <div class="d-flex row no-gutters justify-content-center">
      <!-- 仅一次循环渲染所有卡片,用数据唯一ID当key -->
      <div class="card text-center mt-3" v-for="(price, index) in pricing" :key="price.id">
        <div class="card-body">
          <!-- 动态渲染最优选择标签 -->
          <div class="sale" v-if="price.isBest">Лучший выбор!</div>
          <h5 class="card-title">{{price.lessonCount}} Уроков</h5>
          <h5 
            class="card-title biggerSize" 
            :style="{color: price.isBest ? '#2FAFE5' : ''}"
            style="font-weight: bold; padding-bottom:5px; padding-top:15px;"
          >
            {{price.pricePer.toLocaleString()}} <span class="fas fa-tenge d-inline-block"></span>
          </h5>
          <p class="card-text card-height">за урок</p>
          <p class="card-text">Всего к оплате {{price.totalPrice.toLocaleString()}}тг</p>
          <!-- 动态渲染优惠信息 -->
          <p class="economyTariff" v-if="price.discount">Сэкономить {{price.discount.toLocaleString()}} тг</p>
          <button class="SeeTheCourse mt-5">Начать заниматься</button>
          <a 
            class="collapsed d-lg-none d-md-block" 
            aria-expanded="false"
            href="javascript:;"
            @click.prevent="toggleExpand(index)"
          >
            <span class="fa fa-chevron-down pull-bottom"></span>
          </a>
          <div 
            v-if="price.items.length > 0" 
            class="collapse d-lg-block" 
            :class="{show: price.expand}"
          >
            <div v-for="(item, idx) in price.items" :key="idx">
              <p class="card-text lowerbodyparagraph" :style="{borderBottom: idx === price.items.length-1 ? 'none' : ''}">
                {{item}}
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
</template>

<script>
import $ from 'jquery'
export default {
  data() {
    return {
      pricing: [
        // 10课套餐
        {
          id: 1,
          lessonCount: 10,
          pricePer: 1600,
          totalPrice: 16000,
          discount: null,
          isBest: false,
          expand: false,
          items: [
            "10 онлайн уроков",
            "Интерактивные задания",
            "Безлимитный доступ к материалам"
          ]
        },
        // 30课套餐
        {
          id: 2,
          lessonCount: 30,
          pricePer: 1300,
          totalPrice: 39000,
          discount: 9000,
          isBest: false,
          expand: false,
          items: [
            "30 онлайн уроков",
            "Интерактивные задания",
            "Безлимитный доступ к материалам"
          ]
        },
        // 60课套餐
        {
          id: 3,
          lessonCount: 60,
          pricePer: 1000,
          totalPrice: 60000,
          discount: 16000,
          isBest: true,
          expand: false,
          items: [
            "60 онлайн уроков",
            "Премиальная поддержка",
            "Обратная связ",
            "Безлимитный доступ к материалам"
          ]
        }
      ]
    }
  },
  methods: {
    toggleExpand(index) {
      this.pricing.forEach((item, i) => {
        item.expand = i === index ? !item.expand : false
      })
    }
  }
}
</script>

<style scoped>
.biggerSize {
  /* 原biggerSize样式写这里 */
}
.card-height {
  /* 原card-height样式写这里 */
}
.lowerbodyparagraph {
  /* 原lowerbodyparagraph样式写这里 */
}
</style>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 21:21:01