问题背景
电商商品选择常用以下场景:
- 衣服、手机的选择
- 奶茶的定制选择
UI 层处理要求
- 当用户选择某些属性后,怎么计算每个(自身+其他)属性的可选/可替换的项
- 属性都选中后 → 自动锁定 SKU,显示库存、价格等


你觉得这两种场景是一样的吗?后台能用一个结构返回选项关系吗?如果一个电商平台既要支持衣服、手机等商品、也要支持奶茶等商品,请问应该怎么做?
在解答这些问题前,我们需要先了解他们之前的场景需求。
衣服、手机的场景:可能出现某种尺寸或者型号的商品没有库存或没有生产,从而不能选了。
奶茶的场景:每个选项都可以选择
一、电商 App 的服装选择
1、需求描述
在电商 App(如淘宝、京东、Uniqlo、ZARA)中,用户在商品详情页选择衣服时,常常需要选择:
- 颜色(color):红色、蓝色、黑色
- 尺码(size):S、M、L、XL
- 性别(gender):男款、女款
- 款式(style):连帽、无帽
- 厚度(thickness):常规、加厚
但并不是所有组合都可用,比如
- 有些颜色根本没有男款,eg: 红色没有男款
- 有些款式只支持 M/L 没有 S,eg:男款没有S
- 有些组合明明理论上能配,但没生产
🌟 所以,你无法通过规则自动推导哪些选项合法,只能靠后台上架商品时的 SKU 列表 明确枚举出所有合法组合。
2、推荐的数据结构
枚举 SKU(库存单位)仍然是电商领域最主流、最稳定、最易维护的方式,即便维度变多(颜色、尺码、款式、性别、厚薄、材质等),只要是商品销售中的“最终可买组合”,都建议通过 SKU 列表来做过滤。
原因:电商的核心业务单位就是 SKU
每个实际的商品组合(即将被购买的那个具体“衣服”)就是一个 SKU:
1 | { |
所以上诉电商的问题本质:多属性组合的有效性筛选
这正是一个典型的 多维交叉过滤(multi-dimensional filtering) 或称 SKU(库存单位)选择问题。
如何管理 SPU 和 SKU 的关系:
在电商领域,SPU(Standard Product Unit,标准产品单元) 和 SKU(Stock Keeping Unit,库存单位) 是两个非常重要的概念。它们的关系是 SKU 包含在 SPU 中,而 SPU 是用于描述一个商品的通用属性,SKU 则是根据具体的属性组合(如颜色、尺码等)生成的具体库存项。
- SPU 表:主要存储商品的核心信息和基础属性。
- SKU 表:存储每个商品的具体变体,包括颜色、尺码、价格、库存等详细信息。
数据库关系图:
SPU 表:
spuId name brand category material style description spu_001 T恤 Nike 运动服 棉 连帽 舒适的运动款 SKU 表:
skuId spuId color size gender style price stock weight sku_001 spu_001 红色 S 女款 连帽 199.0 10 0.5 sku_002 spu_001 蓝色 M 女款 无帽 209.0 20 0.6
3、操作逻辑
3.1、入参:选择时候的变量定义
为方便演示,我们假设结构如下
1 | const skuList = [ |
场景举例:
用户原本选择:
1
oldSelected = { color: "黑", size: "M" }
用户进行操作:
1
2
3change = { category: "color", value: "红" } // 用户选择颜色 `"红"`
// 如果用户取消某项(如取消颜色选择)怎么办?
change = { category: "color", value: null } // 用户取消颜色 `"红"`合并出新选项:
1
newSelected = { color: "红", size: "M" }
3.2、核心逻辑:当用户选择某些属性后,怎么计算每个(自身+其他)属性的可选/可替换的项
这些就可以用来禁用/置灰 UI 上不可选的项。
3.2.1、核心逻辑思路
我们以下面操作为例
1 | oldSelected = { color: "红", size: "S", gender: "女款" } |
得到
1 | newSelected = { color: "红", size: "S", gender: "女款", thickness:"常规" }; |
颜色的可替换/选择项计算过程如下,
①去掉 newSelected 中的 color,得到 { size: “S”, gender: “女款”, thickness:”常规” }
②在 skuList 中过滤出符合条件的所有 sku
③从过滤出来的这些SKU中提取 color 的所有可能值,去重后即为color分类的 validOption
3.2.2、核心逻辑示例
场景: 初始无选择 -> 选择”红” -> 选择”S” -> 选择”女款” -> 切为”常规”
1 | // 场景1: |
3.3、结果:若用户所有属性都选了,就直接定位 SKU
1 | const selected = { color: "黑", size: "M" }; |
4、操作逻辑的代码实现
1 | /** |
二、普通奶茶下单
我们将电商衣服的选择扩展到奶茶下单中,
杯型(单选):大杯、超大杯
温度(单选):冰
糖度(单选):标准甜、少糖、无糖
示例:
1 | const skuList = [ |
可以看出当奶茶的所有属性都可以选择的时候,我们得到的 validOptions 为
1 | { |
这也相当于是验证了我们不需要做此计算。
所以理论上可简化为
1 | { |
1、推荐结构
但不同杯型价格不同,所以更合适的结构是下面这样:
1 | { |
即可以任意切换且不影响价格的放在categories中,其他放在sku_list中。
2、其他可能结构
也有些会设计成下面这样子,完全不用sku。
1 | { |
3、其他思考
问:如果选择糖的时候,有的需要增加费用,结果怎么提供?
答:方法①用sku列表时,将糖添加到sku中 或者 方法②不用sku列表时,为糖增加 extra_price。
4、小结
推荐结构:可以任意切换且不影响价格的单选放在categories中,其他放在sku_list中。
三、扩展奶茶下单
杯型(单选):超大杯、大杯、中杯
温度(单选):正常冰、少冰、热
糖度(单选):标准甜、少甜、微甜、无糖
加料(多选):珍珠、葡萄、芋圆、椰果、不另外加
1、需求分析
1.1、功能要求分析
- 分类与选项定义:
- 杯型、温度、糖度:单选
- 加料:多选
- 不同杯型,价格不一样
- 规则限制:
- 选择“无糖”时,加料只能选择“不另外加”,其他全部置灰禁用
- 选择“热”时,加料不能选“葡萄”
请问应该怎么设计数据结构和实现”选择某个分类后自动刷新其他分类可选项并置灰不可选项目”的功能。
1.2、奶茶系统推荐结构
核心思路:
- SKU 负责枚举“杯型 + 温度 + 糖度”这种固定组合(一般对应定价逻辑)
- 加料是用户行为的动态选项,作为 “附加项”附加到 SKU 上
- 不影响 SKU 的价格/库存
- 有自己的校验规则(如「无糖」限制加料)
实际电商和点单系统中常用的做法 ——
将「确定的可枚举组合」用 SKU 管理,
将「不确定的动态选项」如加料、附加服务用“附加项”来处理。
加料不放在SKU中,是因为组合数量会爆炸且冗余:
假设每类属性都有 4 个值,加料 5 个(多选),组合数可能是:
3(杯型) × 3(温度) × 4(糖度) × 2⁵(加料多选组合) = 3 × 3 × 4 × 32 = 1,152 种
2、结构🧱设计拆分
2.1、SKU 定义:仅含主选项
1 | { |
2.2、可多选的附加项(加料)定义
1 | const categories = { |
2.3、规则系统(限制附加项选择)
1 | const rules = [ |
2.4、总结设计优势与场景类似
| 部分 | 用法 | 优点 |
|---|---|---|
| SKU | 负责主商品的组合(杯型、温度、糖度) | ✅ 易管理,价格统一,库存精准 |
| 附加项 | 处理加料等用户增值选项 | ✅ 动态扩展,多选灵活,价格单独计算 |
| 规则系统 | 控制选择互斥/可选性等逻辑 | ✅ 易维护、可配置、逻辑分离 |
使用场景类似
| 场景 | SKU 管控 | 附加项管理 |
|---|---|---|
| 衣服 | 颜色、尺码、版型 | 印花、刺绣、包装 |
| 手机下单 | 颜色、存储、处理器 | 贴膜、延保、耳机 |
| 奶茶/披萨点单 | 杯型、糖度、温度 | 加料、备注、打包 |
| 机票/酒店预订 | 舱位、房型、套餐 | 行李、早餐、保险、接送 |
如你所见:“SKU + 附加项 + 规则” 是一种高扩展、高灵活的标准模型 ✅
3、代码实现
把 加料 从 SKU 属性中拿出来,变成了“附加项”:
拆成两个更新模块更合理:
1 | function updateSKUState(oldSelectedAttrs, change, skuList) { |
分别用于:
- 处理 SKU 属性变化(杯型、温度、糖度)
- 处理加料(附加项)的可选项、禁用项和自动取消逻辑
| 方法名 | 功能 |
|---|---|
updateSKUState |
处理 SKU 类单选属性变化,筛选可选项,找出精确 SKU |
updateAddOnsState |
根据规则动态控制加料的禁用项,并移除当前选择中无效的加料选项 |
3.1、updateSKUState — 处理 SKU 单选属性变化
步骤1:用户选择/替换基础属性(调用 updateSKUState)
1 | let oldSelected = { cupSize: "大杯", temperature: "冰", sweetness: "标准甜" }; |
3.2、 updateAddOnsState — 处理加料限制规则(多选)
步骤2:根据当前属性更新附加选项(调用 updateAddOnsState)
1 | const selectedAttrs = { |
方法实现:
1 | function updateAddOnsState(selectedSKUAttributes, selectedAddOns, rules) { |
总结
从普通奶茶下单示例中,我们可以看出当奶茶的所有属性都可以选择的时候,我们得到的 validOptions 为
1 | { |
这也相当于是验证了我们不需要做此计算。
所以,理论上 cupSize 、 temperature 、 sweetness 等就没必要通过sku方式获得。但当这其中有属性会应影响价格时候(如cupSize),就还是得放在sku中。所以最后推荐的结构如下:
1 | { |
使用此结构,在衣服、手机选择时候也仍然使用。
使用的计算详见上文。
使用有效 SKU 列表:电商场景主流方案,直接枚举合法组合,性能好,扩展性强
使用 rules + if/thenDisable:比较适合你之前描述的“条件式限制”,用于逻辑明确的选项限制