跳转到内容

优化案例:商品卡不同类型代码如何实现

刀刀

7/16/2025

0 字

0 分钟

案例详情

有一个随着类型变化,不断变化的商品卡片,有四种类型,其 UI 结构部分有差距,且后期还有可能增加其他类型,该怎么设计?

下面来看看简单版的 UI: ui

难点分析

  1. 商品类型多,有相似有不同,怎么设计提高复用性
  2. 后续还会增加类型,如何确保可拓展性

组合模式

组合模式核心是把商品按树状结构拆分,然后按需把各个部分组装起来。例如可以划分为以下几点:

  1. 商品容器:规定商品 paddingmargin 等样式,并包含商品信息容器和商品媒体容器
  2. 商品信息容器:包含商品标题、价格、描述等,其中可以更细致的拆分一下
    1. 秒杀条
    2. 热门信息
    3. 标题
    4. 价格
  3. 商品媒体容器:包含视频组件和图片组件
  4. 视频组件
  5. 图片组件

商品容器就是这个树状结构的根,商品信息容器和商品媒体容器是根的子节点,视频组件和图片组件是商品媒体容器的子节点。这样设计的好处是,当商品类型增加时,只需要增加对应的子节点即可,不需要改动根节点,提高了可拓展性。

基础壳子:

vue
<script setup>
// 假设已经引入全部 compoment 内的子组件
</script>
<template>
  <!-- 视频商品卡 -->
  <div v-if="cardType === 'videoCard'">
    <!-- 商品基础容器 -->
    <GoodsContainer>
      <!-- 媒体容器 -->
      <MediaContainer>
        <CardVideo></CardVideo>
        <!-- 商品视频 -->
      </MediaContainer>

      <!-- 信息容器 -->
      <InfoContainer>
        <CardTitle></CardTitle>
        <!-- 商品标题 -->
        <CardPrice></CardPrice>
        <!-- 商品价格 -->
        <CardShopInfo></CardShopInfo>
        <!-- 商家信息 -->
      </InfoContainer>
    </GoodsContainer>
  </div>

  <!-- 秒杀商品视频卡 -->
  <div v-if="cardType === 'scekillvideoCard'">
    <!-- 媒体容器 -->
    <GoodsContainer>
      <MediaContainer>
        <CardVideo></CardVideo>
        <!-- 默认插槽:放商品视频 / 图片 -->
        <template #leftCard>
          <CardScekill title="秒杀中"></CardScekill>
          <!-- 左侧插槽:放秒杀信息 -->
        </template>
      </MediaContainer>

      <!-- 信息容器 -->
      <InfoContainer>
        <CardTitle></CardTitle>
        <!-- 商品标题 -->
        <ScekillBar></ScekillBar>
        <!-- 秒杀条 -->
        <CardPrice></CardPrice>
        <!-- 商品价格 -->
        <ScekillPrice></ScekillPrice>
        <!-- 秒杀价格 -->
      </InfoContainer>
    </GoodsContainer>
  </div>

  <!-- 热门商品视频卡 -->
  <div v-if="cardType === 'hotvideoCard'">
    <!-- 媒体容器 -->
    <GoodsContainer>
      <MediaContainer>
        <CardVideo></CardVideo>
        <!-- 默认插槽:放商品视频 / 图片 -->
        <template #leftCard>
          <CardScekill title="秒杀中"></CardScekill>
          <!-- 左侧插槽:放秒杀信息 -->
          <CardScekill title="热卖中"></CardScekill>
          <!-- 左侧插槽:放秒杀信息 -->
        </template>
      </MediaContainer>

      <!-- 信息容器 -->
      <InfoContainer>
        <CardTitle></CardTitle>
        <!-- 商品标题 -->
        <ScekillBar></ScekillBar>
        <!-- 秒杀条 -->
        <HotInfo></HotInfo>
        <!-- 热卖信息 -->
        <CardPrice></CardPrice>
        <!-- 商品价格 -->
        <ScekillPrice></ScekillPrice>
        <!-- 秒杀价格 -->
      </InfoContainer>
    </GoodsContainer>
  </div>

  <!-- 图片商品卡 -->
  <div v-if="cardType === 'imageCard'"></div>
</template>

策略模式与状态模式

上方的模式是在一个父组件中 v-if 判断要渲染哪个卡片,然后组合对应的子组件。这种模式在卡片数量较少时,代码可读性高,但缺点是当卡片数量增加时,代码会变得冗长,难以维护。

可以使用策略模式,将每种卡片类型抽离成一个独立的组件,父组件引入全部的组件,通过动态组件动态切换卡片的形式。

vue
<template>
  <component :is="cardType"></component>
</template>

<script setup>
import VideoCard from "./VideoCard.vue";
import ScekillVideoCard from "./ScekillVideoCard.vue";
import HotVideoCard from "./HotVideoCard.vue";
import ImageCard from "./ImageCard.vue";

const cardType = "xxx";
const cardList = {
  videoCard: VideoCard,
  scekillVideoCard: ScekillVideoCard,
  hotVideoCard: HotVideoCard,
  imageCard: ImageCard,
};
</script>