商品详情实现SKU选择

191 阅读3分钟

先看看数据效果

image.png

也就是选择Size 下面的Color 要跟着判断是否缺货;相反选择Color也要判断是否有对应的尺码

别想复杂了,也别担心,当你敲完之后,会发现其实很简单,就是拿当前选择的去跟你的字典对比,存在就是有库存,不存在就没库存

先看看后端给的数据结构吧

//这个 是默认返回的sku数据 Size模块下XL 【建议80-100斤】 选中;
//Color classification下 Blue [ Fleece-lined Tops ]选中;
let defaultSku=[
    {
        "paramName": "Size",
        "sort": null,
        "isCommon": null,
        "refSpecId": null,
        "paramValue": "XL 【建议80-100斤】"
    },
    {
        "paramName": "Color classification",
        "sort": null,
        "isCommon": null,
        "refSpecId": null,
        "paramValue": "Blue [ Fleece-lined Tops ]"
    }
];
//这个就是 当前有哪些类别,类别下面有哪些分类;也就是前面图片上的Size和Color classification模块和模块下面对应的选项;
let skuList=[
    {
        "paramName": "Size",
        "sort": 1,
        "isCommon": null,
        "refSpecId": null,
        "paramNameValues": [
            "XL 【建议80-100斤】",
            "2XL 【建议100-115斤】",
        ],
        "paramNameValuesActivity": null
    },
    {
        "paramName": "Color classification",
        "sort": 2,
        "isCommon": null,
        "refSpecId": null,
        "paramNameValues": [
            "Blue [ Fleece-lined Tops ]",
            "Red [ Fleece-lined Tops ]",
            "Purple [ Fleece-lined Tops ]",
        ],
        "paramNameValuesActivity": null
    }
]
//这里就是后端返回的sku数据 也就是一个尺码对应一个颜色的组合
let skuGoodsList=[
    {
        "specValue": [
            {
                "paramName": "Size",
                "paramValue": "XL 【建议80-100斤】"
            },
            {
                "paramName": "Color classification",
                "paramValue": "Blue [ Fleece-lined Tops ]"
            }
        ],
        "goodsStock": 10,//这里就加一个库存数据 需要啥的 让后端给你返回 比如图片 价格
    },
    {
        "specValue": [
            {
                "paramName": "Size",
                "paramValue": "XL 【建议80-100斤】"
            },
            {
                "paramName": "Color classification",
                "paramValue": "Red [ Fleece-lined Tops ]"
            }
        ],
        "goodsStock": 10,//这里就加一个库存数据 需要啥的 让后端给你返回 比如图片 价格
    }
]

当我们拿到这些数据的时候,我们先处理skuGoodsList

我也是网上copy的 先把这个方法存起来

// 计算子集的方法
    export  function bwPowerSet(originalSet) {
        const subSets = []
        const numberOfCombinations = 2 ** originalSet.length
        for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
            const subSet = []
            for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
                if (combinationIndex & (1 << setElementIndex)) {
                    subSet.push(originalSet[setElementIndex])
                }
            }
            subSets.push(subSet)
        }

        return subSets
    }
 //然后我们生成一个字典对象,到时候点击的时候直接去字典对比 就好了
 
 //也就是拿到数据之后 调用下 
 let pathMapList=getPathMap(skuGoodsList)
 
 // 生成有效路径字典对象
    getPathMap(goods){
            let pathMap=this.pathMap
            // 过滤掉 库存不满足的数据
            const effectiveSkus=goods.filter(sku=>sku.goodsStock>0)
            // 子集算法
            effectiveSkus.forEach(item=>{
                    // 匹配paramName组成的数组
                    const selectedValArr=item.specValue.map(val=>val.paramValue)
                    // 使用算法获取子集
                    const valueArrPowerSet=bwPowerSet(selectedValArr)
                    // 得到的子集最终生成字典对象
                    valueArrPowerSet.forEach(v=>{
                            const key=v.join('-')
                            // 如果已经存在 直接添加值 如果不存在就直接存
                            pathMap[key]={
                                    goodsStock:item.goodsStock,
                            }
                    })

            })
            return pathMap
    }
 //通过上面步骤 你就能得到一个字典数据
pathMapList 的数据结构就是这样
 pathMapList={
     "XL 【建议80-100斤】-Red [ Fleece-lined Tops ]":{goodsStock:10},
     "XL 【建议80-100斤】-Blue [ Fleece-lined Tops ]":{goodsStock:10}
     ....
}

到这里我们就处理好了数据的问题

然后我们做样式处理 也就是点击选中和取消选中

  • 先处理下skuList的数据结构,因为我们如果要选中的话,添加一个selected字段来控制是最好的
skuList.forEach(item=>{
     item.paramNameValues=
    item.paramNameValues.map(key=>({name:key,picture:null}))
  })
//这样 上面的 paramNameValues 就变成了对象的形式

//然后我们把数据渲染之后,触发点击事件
// 点击选中和取消选中
clickSpecFn(e,val){//e 就是整个paramNameValues val 就是当前点击的paramNameValues下面的某一个
       //如果当前存在缺货 是不能点击的 
       if(val.disabled) return
       //如果是选中状态 取消选中 这里应该能看懂吧
       if(val.selected){
               val.selected=false
       }else{
               e.paramNameValues.forEach(val=>val.selected=false)
               val.selected=true
       }
       //选择之后 更新数据 去字典里面对比
       this.updateDisabledStatus(skuList,pathMapList)
},
// 切换时更新状态 判断是否有库存 通过disabled 来显示样式
updateDisabledStatus(specs,pathMap){
       specs.forEach(async (item,index)=>{
               const selectedValues=await this.getSelectedValues(specs)
               item.paramNameValues.forEach(val=>{
                       selectedValues[index]=val.name
                       const key=selectedValues.filter(v=>v).join('-')
                       if(pathMap[key]){
                               val.disabled=false
                       }else{
                               val.disabled=true
                       }
               })
       })
}
  • 到这里其实都差不多了,然后给你的代码添加selected和disabled样式即可

  • 可能有更好的方法,这个仅仅只是我学习来的,继续加油