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

Vue多电池SOC进度条单电池独立着色失效问题求解

问题根因
  • 核心问题是重复ID+全局DOM操作:每个ProgressBattery子组件内部的10个进度格都使用了固定重复的ID(v10/v20.../v100),而document.getElementById是全局DOM查询方法,组件按v-for顺序挂载时,后执行mounted逻辑的电池组件,会匹配到页面上所有同ID的元素(包含前面已经渲染完成的其他电池的进度格),直接覆盖之前设置的颜色,最终所有电池颜色会被最后一个挂载的组件统一修改,出现串色。这和bmss数据批量传入没有关系。
  • 实现逻辑不符合Vue框架设计:在mounted钩子里用原生DOM手动修改样式,不属于响应式绑定,后续SOC数值动态变化时颜色不会自动更新,还可能因为DOM渲染时序问题出现样式偶发不生效。
  • 隐藏bug:子组件props的bmss定义为Object类型,默认值却返回了数组,会触发Vue类型校验警告,默认值逻辑失效。
  • 父组件同样存在重复ID问题:v-for循环渲染的多个元素都使用了相同的charging_left_div等固定ID,不符合HTML全局ID唯一的规范,后续如果有DOM查询逻辑会同样出现匹配异常。
修复方案

完全移除原生DOM操作样式、固定ID的写法,改用Vue原生的动态class绑定+计算属性实现颜色逻辑,组件之间样式完全隔离,从根源避免串色。

修复后子组件 ProgressBattery.vue

<template>
  <div class="progress-bar-battery">
    <div class="box">
      <span v-if="bmss.soc >= 100" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 90" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 80" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 70" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 60" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 50" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 40" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 30" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 20" class="item" :class="batteryColorClass"></span>
      <span v-if="bmss.soc >= 10" class="item" :class="batteryColorClass"></span>
    </div>
  </div>
</template>

<script>
export default {
  name: "ProgressBattery",
  props: {
    bmss: {
      type: Object,
      required: true,
      default: function () {
        // 修正原默认值类型错误,Object类型对应返回对象
        return { soc: 0 };
      },
    },
  },
  computed: {
    // 自动计算当前电池对应颜色类,SOC变化时自动更新
    batteryColorClass() {
      const soc = this.bmss.soc;
      if (soc >= 61) return "color-green";
      if (soc >= 21 && soc <= 60) return "color-orange";
      if (soc <= 20) return "color-red";
      return "";
    }
  }
};
</script>

<style scoped>
/* 新增颜色类,scoped作用域保证样式只在当前组件生效,不会污染其他组件 */
.color-green {
  background-color: #4ee533;
}
.color-orange {
  background-color: #FFA500;
}
.color-red {
  background-color: #FF0000;
}
/* 原有的.box、.item等业务样式保持不变即可 */
</style>

父组件修正点

把所有重复的固定ID改成class,循环取值直接用遍历出的bms对象即可,不需要通过索引回源数组取数:

<template>
  <!-- 所有id改为class,避免重复ID问题 -->
  <div class="charging_div frame">
    <div>
      <div class="charging_top_div">
        <div v-for="(bms, index) in bmss" :key="index">
          <div class="charging_left_div">
            <ProgressBattery :bmss="bms" />
            <!-- 直接取当前循环项的soc,更简洁 -->
            <span>{{ bms.soc }}</span>
          </div>
        </div>
      </div>
      <div class="accumulate">
        <p>{{ time }} kW</p>
        <p>{{ power }} kW</p>
      </div>
      <div class="charging_bottom_div">
        <button class="charging_btn" v-on:click="click_stopCharging_btn">
          停止充电
        </button>
      </div>
    </div>
  </div>
</template>
<!-- script部分原有逻辑不需要改动 -->
修复效果
  • 每个电池组件独立计算自身颜色,样式通过scoped隔离,完全不会出现串色问题
  • SOC数值变化时颜色、进度条长度都会自动响应更新,不需要手动操作DOM
  • 修正了props类型、重复ID的隐藏问题,符合Vue开发规范和HTML规范

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:24:32