如何用JavaScript实现类似拼多多的SKU商品选择功能
拼多多式SKU选择功能实现方案
基于你提供的SKU数据结构,要实现点击属性选项后自动展示可搭配的其他属性选项,核心是根据已选属性集合,过滤出所有存在对应有效SKU的属性值,以下是具体实现步骤:
1. 数据预处理(提前整理,提升查询效率)
先把原始SKU数据转换成更易查询的结构,方便后续快速筛选有效组合:
const skus = [/* 你的SKU数组数据 */]; // 存储所有有效属性组合:key为属性组合字符串,value为对应SKU信息 const validCombinations = {}; // 按属性名分组的所有属性值集合 const attributeValues = {}; skus.forEach(sku => { const attrObj = {}; const attrKeyParts = []; sku.attributes.forEach(attr => { attrObj[attr.attr_name] = attr.value_name; attrKeyParts.push(`${attr.attr_name}:${attr.value_name}`); // 填充属性值分组 if (!attributeValues[attr.attr_name]) { attributeValues[attr.attr_name] = new Set(); } attributeValues[attr.attr_name].add(attr.value_name); }); // 生成唯一的组合键(排序后避免顺序问题) const comboKey = attrKeyParts.sort().join(','); validCombinations[comboKey] = { skuId: sku.id, price: sku.price, stock: sku.stock }; }); // 将Set转为数组,方便后续操作 Object.keys(attributeValues).forEach(key => { attributeValues[key] = Array.from(attributeValues[key]); });
2. 维护已选属性状态
用一个对象记录用户当前已选的属性,初始为空:
// 示例:选中红色后变为 { color: "red" } const selectedAttributes = {};
3. 属性选项点击逻辑
处理用户点击属性值的交互,更新已选状态并触发可选值计算:
function handleAttributeClick(attrName, valueName) { // 切换选中/取消选中状态 if (selectedAttributes[attrName] === valueName) { delete selectedAttributes[attrName]; } else { selectedAttributes[attrName] = valueName; } // 计算并更新所有属性的可选状态 updateAvailableAttributes(); }
4. 核心:计算可选属性值
根据已选属性,筛选出所有能组合出有效SKU的属性值:
function updateAvailableAttributes() { // 先筛选出包含已选属性的所有有效组合 let filteredCombos = Object.keys(validCombinations); // 按已选属性过滤组合 Object.entries(selectedAttributes).forEach(([attrName, value]) => { filteredCombos = filteredCombos.filter(combo => combo.includes(`${attrName}:${value}`)); }); // 初始化所有属性值为不可选 const availableAttrs = {}; Object.keys(attributeValues).forEach(attrName => { availableAttrs[attrName] = {}; attributeValues[attrName].forEach(value => { availableAttrs[attrName][value] = false; }); // 已选中的属性值默认可选 if (selectedAttributes[attrName]) { availableAttrs[attrName][selectedAttributes[attrName]] = true; } }); // 遍历筛选后的组合,标记可选的属性值 filteredCombos.forEach(combo => { const attrs = combo.split(',').map(item => { const [name, val] = item.split(':'); return { name, val }; }); attrs.forEach(({ name, val }) => { // 未选中的属性,标记其出现的值为可选 if (!selectedAttributes[name]) { availableAttrs[name][val] = true; } }); }); // 更新UI状态 renderAttributeOptions(availableAttrs); }
5. UI层更新
根据计算出的可选状态,更新每个属性选项的样式和可交互性:
function renderAttributeOptions(availableAttrs) { document.querySelectorAll('.attr-option').forEach(btn => { const attrName = btn.dataset.attr; const valueName = btn.dataset.value; const isAvailable = availableAttrs[attrName][valueName]; const isSelected = selectedAttributes[attrName] === valueName; // 更新样式与禁用状态 btn.classList.toggle('selected', isSelected); btn.classList.toggle('disabled', !isAvailable && !isSelected); btn.disabled = !isAvailable && !isSelected; }); // 若所有属性都已选中,展示对应SKU的价格、库存 if (Object.keys(selectedAttributes).length === Object.keys(attributeValues).length) { const comboKey = Object.entries(selectedAttributes) .map(([name, val]) => `${name}:${val}`) .sort() .join(','); const skuInfo = validCombinations[comboKey]; if (skuInfo) { document.getElementById('sku-price').textContent = skuInfo.price; document.getElementById('sku-stock').textContent = skuInfo.stock; } } }
6. 边界情况处理
- 取消所有选中时,调用
updateAvailableAttributes会自动恢复所有选项为可选 - 库存为0的SKU,可在预处理阶段从
validCombinations中排除,或标记为不可选 - 若筛选后无有效组合,可提示用户调整已选属性
内容的提问来源于stack exchange,提问作者oren
相关产品推荐
相关产品推荐

