销售属性与sku傻傻分不清楚

267 阅读2分钟

零、直观了解销售属性和sku

销售属性==== [['红色','黄色','蓝色'],['xl','xxl','xxxl'],['全棉','冰沙']]

sku =======  ['黄色', 'xl', '冰纱'],    ['红色', 'xl', '冰纱']  .......                

一、如何根据销售属性,组合出所有可能的sku

(1)应用场景

B端商城发布商品的时候,就会根据销售属性组合出所有的sku

(2)直观看一下,到底是个什么事

其实就是数学的组合问题:

销售属性=[['红色', '黄色', '蓝色'], ['xl', 'xxl', 'xxxl'], ['全棉', '冰沙']]

sku=?

(3)头脑风暴一下

你有什么想法??????

(4)分析问题

首先想到的是嵌套循环,但是嵌套循环有个问题,就是对于嵌套层次固定的可以,但是对于嵌套层次不固定的就无能为力了。

接着我们就会想到递归了,因为递归本来就是嵌套调用,而且只要我们在方法内部使用循环,不就成了嵌套循环了。

下面画图稍作分析:会得出一个问题(运行时状态我们不知道)

image.png

经过上图分析,大概知道了使用递归替换嵌套循环,需要解决一个问题,就是怎么保存运行时的状态。换句话说,怎么知道当前执行到了哪一层。递归的图示只是表示代码的执行过程,不是源代码,递归的源代码可能只有两行:一个for 和 一个递归调用

现在想一下,假设 A 调用 B,B 再调用 C,C 执行完返回给 B,B 再执行完返回给 A,哪种数据结构最适合管理它们?没错,是 stack,因为过程调用具有 先进后出的特点

【图示说明栈和调用的对应关系!!!!!!】

结论:如果我调用函数就入栈, 函数执行完成就出栈,这样是不是就可以看栈顶元素就知道当前正在执行的是哪个函数,以及根据栈中的元素个数,知道当前执行的是第几层嵌套

最终选择使用:递归+栈

(5)【递归实现法】

//递归实现的算法:         
let saleAttr2 = [['红色','黄色','蓝色'],['xl','xxl','xxxl'],['全棉','冰沙']]         function deal(stack=[],result=[]){             
// 递归的结束条件:栈满了             
if(stack.length === saleAttr2.length){               
result.push([...stack])             
// 递归条件              
}else{               
for(const item of saleAttr2[stack.length]){                   
stack.push(item)                  
deal(stack,result)                  
stack.pop()               
}             
}             
return result         
}         
console.log(JSON.stringify(deal()))         
console.log(deal().length)

(6)上帝给你留了一扇门——迭代实现法

算法说明:

1、定义一个结果数组

2、让结果数组依次和销售属性进行组合,每次组合的结果覆盖之前的结果

(7)迭代实现

<script>       
// 使用循环的算法:         
const saleAttr=[['红色','黄色','蓝色'],['xl','xxl','xxxl'],['全棉','冰沙']]         const getCombination=(saleAttr)=>{             
let resultArry=[];             
saleAttr.forEach((saleAttrItem)=>{                 
if(resultArry.length===0){                     
resultArry=saleAttrItem                 
}else{                     
const emptyArray=[];                     
resultArry.forEach((item)=>{                         saleAttrItem.forEach((value)=>{                             emptyArray.push(Array.isArray(item)?[...item,value]:[item,value])                         })                     
})                     
resultArry=emptyArray                 
}             
});             
return resultArry;         
}         
console.log(JSON.stringify(getCombination(saleAttr)))         console.log(getCombination(saleAttr).length)

二、如何根据sku,判断销售属性是否可选

(1)好图省千言

(2)应用场景

C端商城

(3)线上购物来源于线下

线下买鞋子:

客户:老板,有没有白鞋子?

老板:有啊(在货架上查找一下)

客户:有没有尺寸是40码的

老板:有啊(在货架上查找一下)

客户:有没有带网子的

老板:有啊(在货架上查找一下)

购物成功!!!

(4)实现说明

必须明确的点:一个sku对应一件实实在在的物品,而一个商品名称可能包括多种sku。

例如:我说"mac笔记本"  和我说"2019版的银色的mac pro,内存8g的笔记本"。听到哪一个头脑中的画面更加具体

                        

核心逻辑:假设法。

以下面的“黄色”为例:

1、黄色能不能选呢?  我们假定能选。

2、我们就去找有没有颜色等于黄色的sku(鞋子),没有就不能选,有则看其他的条件

3、再看除了颜色以外的其他销售属性:也就是看用户对其他销售属性的要求:比如尺寸选了xl, 材料选了全棉,就按照要求过滤

4、最后如果找到了sku(鞋子),就说明这个黄色可以选择,反之不行

记住两句话:

1、对当前选项进行过滤

2、对当前选项以外的销售属性进行过滤

(5)代码是实现

<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>     
<script src="./node_modules/vue/dist/vue.js"></script> 
</head> 
<style>     
.border{         
border:2px solid red;     
} </style> 
<body>    
<div id='app'>         
<div v-for="(item) in saleAttr3">             
<button style="margin:10px;" @click="dealCheck(item,checkItem)" :class="{'border':item.check===checkItem.name}" :disabled="!checkItem.canClick" v-for = "(checkItem) in item.list">{{checkItem.name+checkItem.canClick}}</button>
</div>    
</div>     
<script>         
new Vue({             
el: '#app',             
data: {                 
    saleAttr3 :[{                     
        name: '颜色',                     
        list: [                         
           { name: '黄色' },                         
           { name: '红色' },                         
           { name: '白色' }                     
        ]                 
        }, {                     
        name: '尺寸',                     
        list: [                         
        { name: 'xl' },                         
        { name: 'xxl' },                         
        { name: 'xxxl' }                     
        ]                 }, 
        {                     
        name: '材料',                     
        list: [                         
        { name: '全棉' },                         
        { name: '冰纱' }                     
        ]                 
        }],                 
        skus :[                     
        ['黄色', 'xl', '冰纱'],                     
        // ['黄色', 'xl', '全棉'],                     
        // ['黄色', 'xxl', '冰纱'],                     
        // ['红色', 'xl', '冰纱'],                     
        // ['白色', 'xl', '冰纱'],                     
        // ['黄色', 'xxxl', '冰纱'],                     
        // ['黄色', 'xl', '全棉'],                     
        ['红色', 'xxl', '全棉'],                 
        ]             
        },             
        mounted () {                 
            this.computeCanClick();             
        },             
        methods: {                 
            dealCheck(saleAttrItem,optionItem){                     
            // 如果点击的选项刚好是选中的,直接去掉选中                     
            // if(saleAttrItem.check === optionItem.name){                                 //      this.$set(saleAttrItem,"check","")                     
            // }else{                     
            //     this.$set(saleAttrItem,"check",optionItem.name)                         // }                     
            // 优化一下                    
            let checkName =  saleAttrItem.check === optionItem.name?"":optionItem.name                    
            this.$set(saleAttrItem,"check",checkName)                    
            //重新计算一下哪些可以选择,哪些不能选择 
            this.computeCanClick();                    },                 
            // 根据sku,找到哪些销售属性不能操作                 
            computeCanClick() {                     
            // 循环销售属性            
            this.saleAttr3.forEach((saleAttrItem) => {     
            // 循环销售属性选项                    
            saleAttrItem.list.forEach((checkItem => {          
            let skus = this.findSku(saleAttrItem.name, checkItem.name)     
            let sign = false                            
            sign = skus && skus.length > 0   
            this.$set(checkItem,"canClick",sign)                         
            }))                     
            })                 
            },                 
            // saleAttrName销售属性的名字:颜色,checkItemName选项的名字:红色  
            findSku(saleAttrName, checkItemName) {    
            // 第一步过滤:过滤出符合条件的sku,过滤出包含红色的sku       
            let fitSku = this.skus.filter((skuItem) => {   
            return skuItem.includes(checkItemName)          
            })                    
            // 第二步过滤:过滤除了颜色以外的销售属性        
            this.saleAttr3.forEach((saleAttrItem) => {     
            if (saleAttrItem.name !== saleAttrName) {     
            fitSku = fitSku.filter((skuItem) => {      
            // 当前销售属性已经选择了                              
            if (saleAttrItem.check) {     
            return skuItem.includes(saleAttrItem.check)  
            }                            
            })                     
            }                  
            })           
            return fitSku;   
            }            
            }       
            })    
            </script> 
            </body> 
            </html>

更多学习视频学习资料请参考:B站搜索“我们一起学前端”  

我们一起学前端的个人空间_哔哩哔哩_Bilibili