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

如何将三个相似Vue组件合并为单一可复用组件?遵循DRY原则优化

当然可以合并成一个可复用组件!

这正是DRY(Don't Repeat Yourself)原则的典型应用场景——我们只需要把三个组件的**公共部分(结构、基础样式)提取出来,将差异部分(颜色、计算逻辑)**做成可配置项,就能实现高度复用。下面给你两种最优方案,根据你的场景选择:

方案一:Props + 内部封装固定逻辑(适合逻辑稳定的场景)

如果这三种计算逻辑是固定需求,不会频繁新增,推荐这种方案:组件内部封装好三种计算逻辑,通过Props传递颜色、计算类型和对应参数,父组件使用时只需简单配置。

复用组件代码

<template>
  <div class="square-box" :style="{ backgroundColor: color }">
    {{ computedValue }}
  </div>
</template>

<script setup>
import { computed } from 'vue';

const props = defineProps({
  // 方形背景色(必填)
  color: {
    type: String,
    required: true
  },
  // 计算类型:限定为三种固定逻辑
  computeType: {
    type: String,
    required: true,
    validator: (val) => ['percentage', 'ceil', 'average'].includes(val)
  },
  // 计算所需的参数数组,根据类型传入对应数量的值
  values: {
    type: Array,
    required: true
  }
});

// 计算最终显示的值
const computedValue = computed(() => {
  switch (props.computeType) {
    case 'percentage':
      // 红色组件逻辑:两个值计算百分比
      if (props.values.length !== 2) throw new Error('百分比计算需要传入2个值');
      const [num, total] = props.values;
      return `${((num / total) * 100).toFixed(1)}%`;
    case 'ceil':
      // 蓝色组件逻辑:浮点值向上取整
      if (props.values.length !== 1) throw new Error('向上取整需要传入1个值');
      return Math.ceil(props.values[0]).toString();
    case 'average':
      // 绿色组件逻辑:三个值取平均值
      if (props.values.length !== 3) throw new Error('平均值计算需要传入3个值');
      const sum = props.values.reduce((acc, cur) => acc + cur, 0);
      return (sum / 3).toFixed(1);
    default:
      return '';
  }
});
</script>

<style scoped>
.square-box {
  width: 100px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff; /* 保证文字与背景对比清晰 */
  border-radius: 4px; /* 可选:增加一点圆角优化视觉 */
}
</style>

父组件使用示例

<!-- 原红色百分比组件 -->
<SquareBox 
  color="#ff4444" 
  computeType="percentage" 
  :values="[25, 100]" 
/>

<!-- 原蓝色向上取整组件 -->
<SquareBox 
  color="#33b5e5" 
  computeType="ceil" 
  :values="[3.1415]" 
/>

<!-- 原绿色平均值组件 -->
<SquareBox 
  color="#99cc00" 
  computeType="average" 
  :values="[10, 20, 30]" 
/>

方案二:Props + 自定义计算函数(适合灵活扩展的场景)

如果未来可能需要新增更多不同的计算逻辑,或者希望把计算逻辑交给父组件控制,推荐这种方案:组件只负责渲染方形容器,计算逻辑通过函数Props传入,完全解耦渲染和业务逻辑。

复用组件代码

<template>
  <div class="square-box" :style="{ backgroundColor: color }">
    {{ computedValue }}
  </div>
</template>

<script setup>
import { computed } from 'vue';

const props = defineProps({
  color: {
    type: String,
    required: true
  },
  // 父组件传入的计算函数
  computeFn: {
    type: Function,
    required: true
  },
  // 计算函数所需的参数数组
  computeParams: {
    type: Array,
    default: () => []
  }
});

// 调用父组件传入的函数计算值
const computedValue = computed(() => {
  return props.computeFn(...props.computeParams);
});
</script>

<style scoped>
.square-box {
  width: 100px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  border-radius: 4px;
}
</style>

父组件使用示例

<!-- 原红色百分比组件 -->
<SquareBox 
  color="#ff4444" 
  :computeFn="(num, total) => `${((num/total)*100).toFixed(1)}%`"
  :computeParams="[25, 100]"
/>

<!-- 原蓝色向上取整组件 -->
<SquareBox 
  color="#33b5e5" 
  :computeFn="(val) => Math.ceil(val).toString()"
  :computeParams="[3.1415]"
/>

<!-- 原绿色平均值组件 -->
<SquareBox 
  color="#99cc00" 
  :computeFn="(a,b,c) => ((a+b+c)/3).toFixed(1)"
  :computeParams="[10,20,30]"
/>

方案选择建议

  • 如果你的三种计算逻辑是长期固定的,不会轻易新增,选方案一:逻辑内聚在组件内部,父组件使用更简洁,维护成本更低。
  • 如果未来可能要添加更多自定义计算逻辑,或者需要让组件适配更多场景,选方案二:完全解耦渲染和业务逻辑,灵活性拉满。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:40:25