Vue实现商品多规格选择功能

发布于:2024-05-10 ⋅ 阅读:(24) ⋅ 点赞:(0)

背景

在电商网站中,产品有多个规格选择,比如颜色、尺寸等规格。颜色的色值和尺寸的大小等组合组成1个SKU(Stock Keeping Unit,库存量单位)
这在做电商相关的项目经常见。 工作中应该会遇到。
当然也可以用第三方例如 vant组件库提供的SKU选择器,不过用别人的组件就要按照别人的数据格式,就很难受。

下面是用vue3的简单实现。

先上效果

实现思路

例如一个商品有多个规格(属性),内含多个规格值(属性值):
颜色:黑色、白色
尺寸:大、中、小

计算sku最终生成的数量
假设颜色的规格值数量为m1,尺寸的规格值数量为m2
sku数量= m1*m2

要实现的几个操作:

  • 根据 sku 列表生成映射,包含的属性作为唯一key(不用担心会重复,因为录入产品时候会限制不能录入相同名称的规格名称)。后续根据key取数据。
  • 处理选择后的操作。
  • 处理库存不足不可选择的情况。

代码实现

<template>
  <div class="sku-group" v-for="(values, name) in attrs" :key="name">
    <div class="sku-title">{{ name }}</div>
    <div class="sku-option" v-for="value in values" :key="value"
      :class="{ 'sku-option-selected': selectedAttrs[name] === value, 'sku-option-disabled': !isOptionAvailable(name, value) }"
      @click="selectOption(name, value)">
      {{ value }}
    </div>
  </div>
  <div class="sku-selected">当前选中的 SKU: {{ selectedSku }}</div>
  <div class="sku-message">{{ message }}</div>
</template>

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

    // 创建一个 SKU 映射,键是 SKU 的属性,值是 SKU 对象
    function generateSkuMap(skus) {
      const map = {};
      for (let sku of skus) {
        let key = JSON.stringify(sku.attrs);
        map[key] = sku;
      }
      return map;
    }

    // 找到第一个有库存的 SKU
    function findFirstAvailableSku(skus) {
      return skus.find(sku => sku.stock > 0);
    }

    // 初始化状态
    const state = reactive({
      skus: [
        {id:1, attrs:{'颜色':'黑色', '尺寸':'大'}, stock:100},
        {id:2, attrs:{'颜色':'黑色', '尺寸':'中'}, stock:100},
        {id:3, attrs:{'颜色':'黑色', '尺寸':'小'}, stock:0},
        {id:4, attrs:{'颜色':'白色', '尺寸':'大'}, stock:100},
        {id:5, attrs:{'颜色':'白色', '尺寸':'中'}, stock:0},
        {id:6, attrs:{'颜色':'白色', '尺寸':'小'}, stock:100},
      ],
      attrs: {
        '颜色': ['黑色', '白色'],
        '尺寸': ['大', '中', '小'],
      },
      selectedAttrs: {},
      message: '',
    });

    // 创建 SKU 映射
    const skuMap = computed(() => generateSkuMap(state.skus));

    // 获取当前选中的 SKU
    const selectedSku = computed(() => {
      let key = JSON.stringify(state.selectedAttrs);
      return skuMap.value[key];
    });

    // 检查一个选项是否可用
    const isOptionAvailable = (name, value) => {
      let testAttrs = {...state.selectedAttrs, [name]: value};
      let key = JSON.stringify(testAttrs);
      return skuMap.value[key] && skuMap.value[key].stock > 0;
    };

    // 选择一个选项
    const selectOption = (name, value) => {
      if (isOptionAvailable(name, value)) {
        state.selectedAttrs[name] = value;
        state.message = '';
      } else {
        state.message = `${JSON.stringify({...state.selectedAttrs, [name]: value})} 暂无库存`;
      }
    };

    // 自动选择第一个有库存的 SKU
    const firstSku = findFirstAvailableSku(state.skus);
    if (firstSku) {
      state.selectedAttrs = {...firstSku.attrs};
    }
    // 导出响应式引用
    const { skus, attrs, selectedAttrs, message } = toRefs(state);
</script>
<style>
  .sku-group {
    margin-bottom: 1em;
  }

  .sku-option {
    display: inline-block;
    margin: 0.5em;
    padding: 0.5em;
    border: 1px solid #ccc;
    cursor: pointer;
  }

  .sku-option-disabled {
    color: #ccc;
    cursor: not-allowed;
  }

  .sku-option-selected {
    background-color: #b8d3f1;
  }
</style>

总结

  • sku数据处理:这块主要是对sku列表进行存到map里面,方便后续存取。

  • 展示页面:然后遍历颜色尺寸这些规格以及它们的规格值数据到页面。

  • 选择处理:获取到当前选择的 规格和规格值进行替换已选中的规格值(这是一个对象,只需要把规格作为属性值替换即可)。然后JSON序列化字符串作为key去查找sku列表。找到所属sku数据。判断库存,是否可以选择。

主要是对sku数据的处理。明白实现原理之后,可以方便的移植到小程序、uniapp之类的环境中。


网站公告

今日签到

点亮在社区的每一天
去签到