零、直观了解销售属性和sku
销售属性==== [['红色','黄色','蓝色'],['xl','xxl','xxxl'],['全棉','冰沙']]
sku ======= ['黄色', 'xl', '冰纱'], ['红色', 'xl', '冰纱'] .......
一、如何根据销售属性,组合出所有可能的sku
(1)应用场景
B端商城发布商品的时候,就会根据销售属性组合出所有的sku
(2)直观看一下,到底是个什么事
其实就是数学的组合问题:
销售属性=[['红色', '黄色', '蓝色'], ['xl', 'xxl', 'xxxl'], ['全棉', '冰沙']]
sku=?
(3)头脑风暴一下
你有什么想法??????
(4)分析问题
首先想到的是嵌套循环,但是嵌套循环有个问题,就是对于嵌套层次固定的可以,但是对于嵌套层次不固定的就无能为力了。
接着我们就会想到递归了,因为递归本来就是嵌套调用,而且只要我们在方法内部使用循环,不就成了嵌套循环了。
下面画图稍作分析:会得出一个问题(运行时状态我们不知道)
经过上图分析,大概知道了使用递归替换嵌套循环,需要解决一个问题,就是怎么保存运行时的状态。换句话说,怎么知道当前执行到了哪一层。递归的图示只是表示代码的执行过程,不是源代码,递归的源代码可能只有两行:一个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站搜索“我们一起学前端”