sku排列算法实现商品规格属性组合

背景

前两年做过一个电商系统的新建商品模块,记忆中比较有难点的是在新增商品的sku规格时,需要把每个规格名称下的规格属性一一组合起来。因此在这里稍微的写个小demo记录下这种规格属性组合的思路😁

数据结构

// 假设一个sku的集合数据结构是这样的
  /*
    [
      { 
        name: '内存', // 规格名称
        // 规格属性列表
        list: [
          { name: '128GB' },
          { name: '256GB' },
          { name: '512GB' },
        ]
      },
      ...
    ]
  */

新增一个data.json文件用于存放模拟数据

// data.json
export default [
  {
    "name": "机型",
    "list": [
      { "name": "iPhone 13"},
      { "name": "iPhone 14"}
    ]
  },
  {
    "name": "颜色",
    "list": [
      { "name": "蓝色"},
      { "name": "白色"}
    ]
  },
  {
    "name": "存储容量",
    "list": [
      { "name": "64GB"},
      { "name": "128GB"}
    ]
  }
]

实现商品规格属性组合数据处理

将sku集合的属性列表 -- 集合成这样的格式[ [ {...},{...},...],[{...},{...} ] ] 二维数组的数

const sku_list = []
function composeSkuList() {
  for(const { list } of skuData) {
    sku_list.push(list)
  }
 }
composeSkuList()

处理的结果打印是这样的:

 sku排列算法 -- 将二维数组使用扩展运算符传入参数,调用数组的reduce循环,在内部使用双重循环concat拼接后存储到全局变量中

function cartesianProductOf () {
  return Array.prototype.reduce.call(arguments, function(a, b) {
    const result = []  // 存储拼接的结果
    a.forEach(item_a => {
      b.forEach(item_b => { 
        result.push(item_a.concat(item_b))
      })
    })
  return result
  }, [[]])
 }
console.log(cartesianProductOf(...sku_list))

打印的结果是这样的

 

现在构造渲染的表格数据,调用排列sku的方法

function composeTableData (sku_list) {
  // 获取组合好的sku规格数据
  const arr = cartesianProductOf(...sku_list)
  return arr.map(item => {
    return {
      sku: item,  // 组合好的规格[{...},{...}]
      oprice: 10, // 销售价
      cprice: 5, // 成本价
      stock: 100 // 库存
    }
  })
}

以上就是处理商品规格组合的逻辑

结合表格展示商品规格属性组合

下面是完整的代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    th, td{
      padding: 12px;
    }
  </style>
</head>
<body>
  <div>
    <table border cellspacing="0" cellpadding="0" id="table"></table>
  </div>
</body>
</html>
<script type="module">
// 处理数据
// 假设一个sku的集合数据结构是这样的
  /*
  [
    { 
      name: '内存', // 规格名称
      // 规格属性列表
      list: [
        { name: '128GB' },
        { name: '256GB' },
        { name: '512GB' },
      ]
    },
    ...
  ]
*/

 // 引入数据
 import skuData from './data.js'

let sku_list = [] // 村粗规格属性列表
let tableData = [] // 存储表格数据

let colSkuValue = [] // 存储商品规格渲染列的名称

// 先将sku集合的属性列表 -- 集合成这样的格式[[{...},{...},...],[{...},{...}]] 二维数组的数组对象结构格式
function composeSkuList() {
  let skuList = []
  for(const { list } of skuData) {
    skuList.push(list)
  }
  return skuList
}

// sku排列算法 -- 将二维数组使用扩展运算符传入参数,调用数组的reduce循环,在内部使用双重循环concat拼接后存储到全局变量中
function cartesianProductOf () {
  return Array.prototype.reduce.call(arguments, function(a, b) {
    const result = []  // 存储拼接的结果
    a.forEach(item_a => {
      b.forEach(item_b => { 
        result.push(item_a.concat(item_b))
      })
    })
  return result
  }, [[]])
 }

// 构造渲染的表格数据
function composeTableData (data) {
  console.log(data, 'data')
  // 获取组合好的sku规格数据
  const arr = cartesianProductOf(...data)
  return arr.map(item => {
    return {
      sku: item,  // 组合好的规格[{...},{...}]
      oprice: 10, // 销售价
      cprice: 5, // 成本价
      stock: 100 // 库存
    }
  })
}

// 构造需要渲染商品规格名称的列
function composeColSkuValue () {
  return skuData.map(item => item.name)
}

sku_list = composeSkuList()
tableData = composeTableData(sku_list)
colSkuValue = composeColSkuValue()
console.log(tableData, 'composeTableData')
console.log(colSkuValue, 'colSkuValuecolSkuValue')



// 渲染表格的处理方法
let column = [
  {name: "商品规格",rowspan: 1,colspan: 1,width: ""},
  {name: "销售价",rowspan: 2,width: "80"},
  {name: "成本价",rowspan: 2,width: "80"},
  {name: "库存",rowspan: 2,width: "80"}
]
let table = document.getElementById('table')
const thead = document.createElement('thead');
table.appendChild(thead)
const theadTr = document.createElement('tr')
const colSkuTr = document.createElement('tr')
thead.append(theadTr)
thead.append(colSkuTr)
column[0].colspan = colSkuValue.length // 第一列随着有多少个规格名称就跨几列
// S 创建表头
for(let i = 0; i < column.length; i++) {
  const th = document.createElement('th')
  th.innerHTML = column[i].name
  th.rowSpan = column[i].rowspan
  th.colSpan = column[i].colspan
  th.width = column[i].width
  theadTr.appendChild(th)
}
for(let i = 0; i < colSkuValue.length; i++) {
  const th = document.createElement('th')
  th.innerHTML = colSkuValue[i]
  colSkuTr.appendChild(th)
}
// E 创建表头

// S 创建表体
const tbody = document.createElement('tbody')
const keyArr = ['oprice', 'cprice', 'stock']
for(let i = 0; i < tableData.length; i++) {
const tbodyTr = document.createElement('tr')
for(let skuIndex = 0; skuIndex < tableData[i].sku.length; skuIndex++) {
  const sku = tableData[i].sku[skuIndex]
  const skuTd = document.createElement('td')
  skuTd.innerHTML = sku.name
  tbodyTr.appendChild(skuTd)
}
for(const key of keyArr) {
  const td = document.createElement('td')
  td.innerHTML = tableData[i][key]
  tbodyTr.appendChild(td)
}
tbody.appendChild(tbodyTr)
}
table.appendChild(tbody)
// E 创建表体
</script>

最后展示的结果如下图

~~~end~~~

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个React组件的代码实现,用于实现前端SKU算法商品规格选择功能: ```jsx import React, { useState, useEffect } from "react"; const SKUSelector = ({ skuList }) => { const [selectedValues, setSelectedValues] = useState({}); const [availableOptions, setAvailableOptions] = useState({}); useEffect(() => { // 初始化可选项列表 let options = {}; skuList.forEach((sku) => { sku.attributes.forEach((attr) => { if (!options[attr.name]) { options[attr.name] = [attr.value]; } else if (!options[attr.name].includes(attr.value)) { options[attr.name].push(attr.value); } }); }); setAvailableOptions(options); }, [skuList]); const handleValueChange = (name, value) => { // 更新已选项列表 setSelectedValues({ ...selectedValues, [name]: value }); // 根据已选项列表筛选可选项列表 let options = { ...availableOptions }; for (let attrName in selectedValues) { if (attrName !== name) { skuList.forEach((sku) => { if ( sku.attributes.find((attr) => attr.name === attrName)?.value !== selectedValues[attrName] ) { options[attrName] = options[attrName].filter( (option) => option !== selectedValues[attrName] ); } }); } } setAvailableOptions(options); }; const getAvailableValues = (name) => { // 获取指定规格属性的可选项列表 return availableOptions[name] || []; }; const getSelectedSKU = () => { // 根据已选项列表获取SKU信息 let selectedSKU = null; skuList.forEach((sku) => { let matches = true; sku.attributes.forEach((attr) => { if (selectedValues[attr.name] !== attr.value) { matches = false; } }); if (matches) { selectedSKU = sku; } }); return selectedSKU; }; return ( <div> {skuList.length > 0 ? ( skuList[0].attributes.map((attr) => ( <div key={attr.name}> <label>{attr.name}:</label> <select value={selectedValues[attr.name] || ""} onChange={(e) => handleValueChange(attr.name, e.target.value)} > <option value="">请选择</option> {getAvailableValues(attr.name).map((option) => ( <option key={option} value={option}> {option} </option> ))} </select> </div> )) ) : ( <div>暂无商品信息</div> )} {getSelectedSKU() ? ( <div> <p>已选规格:{JSON.stringify(selectedValues)}</p> <p>剩余库存:{getSelectedSKU().stock}</p> </div> ) : ( <div>请选择完整规格属性</div> )} </div> ); }; export default SKUSelector; ``` 该组件接受一个SKU列表作为props,每个SKU包含一个属性列表和一个库存数量。在组件中,首先使用useEffect钩子初始化可选项列表,然后使用useState钩子管理已选项列表和可选项列表的状态。 当用户选择某个规格属性值时,组件会根据已选项列表筛选可选项列表,并更新已选项列表。当用户选择所有规格属性值后,组件会根据已选项列表获取相应的SKU信息,并显示剩余库存量。 该组件仅为示例代码,具体实现方式可能因业务需求而异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值