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~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值