实现目标
这里举一个例子来说明
图一
现在有这一些规格可以供我们选择,但是这其中只有少部分规格是存在的,其他的规格是不存在的(这里还应该包括可销售商品数量为零的情况),不存在的规格不应该让用户可选中。以下为可以选择的规格
{"sku_list":[
[
"specs":[
{key_id: 1, key: "颜色", value_id: 45, value: "金属灰"},
{key_id: 3, key: "图案", value_id: 9, value: "七龙珠"},
{key_id: 4, key: "尺码", value_id: 14, value: "小号 S"}
]
]
[
"specs":[
{key_id: 1, key: "颜色", value_id: 42, value: "青芒色"},
{key_id: 3, key: "图案", value_id: 10, value: "灌篮高手"},
{key_id: 4, key: "尺码", value_id: 15, value: "中号 M"}
]
]
[
"specs":[
{key_id: 1, key: "颜色", value_id: 42, value: "青芒色"},
{key_id: 3, key: "图案", value_id: 11, value: "圣斗士"},
{key_id: 4, key: "尺码", value_id: 16, value: "大号 L"}
]
]
[
"specs":[
{key_id: 1, key: "颜色", value_id: 44, value: "橘黄色"},
{key_id: 3, key: "图案", value_id: 9, value: "七龙珠"},
{key_id: 4, key: "尺码", value_id: 14, value: "小号 S"}
]
]
]
}
代码片段一
比如用户选择颜色为金属灰,那么图案只有七龙珠可选,尺码只有小号 S可选,其他颜色和尺码都不应该可以选择,如下图所示
图二
同时还应该考虑反选的情况,比如这里已经选择了金属灰,如果用户取消金属灰,那么颜色、图案、尺码应该变为全部可以选择。说完了最终实现的效果,下面再看看具体的实现思路
实现思路
一、获取数据,计算可选规格
服务器提供的数据可能只是上面例子中代码片段一那样,这时就需要整理,这里我整理结果如下(根据自己的实际情况处理),其中select_type表示用户的选择状态(unselected表示未选中,selected表示选中,locking表示不可选中),因为是初始值,所以默认都应该是可以选中,把整理的数据渲染到页面上,如图一
[
{
key: "颜色",
key_id: 1,
value: [
{value: "金属灰", value_id: 45, select_type: "unselected"},
{value: "青芒色", value_id: 42, select_type: "unselected"},
{value: "橘黄色", value_id: 44, select_type: "unselected"}
]
},
{
key: "图案",
key_id: 3,
value: [
{value: "七龙珠", value_id: 9, select_type: "unselected"},
{value: "灌篮高手", value_id: 10, select_type: "unselected"},
{value: "圣斗士", value_id: 11, select_type: "unselected"}
]
},
{
key: "尺码",
key_id: 4,
value: [
{value: "小号 S", value_id: 14, select_type: "unselected"},
{value: "中号 M", value_id: 15, select_type: "unselected"},
{value: "大号 L", value_id: 16, select_type: "unselected"}
]
}
]
代码片段二
二、处理用户点击事件
1、已选中的规格
当用户点击其中一个规格,先将已经选中的规格保存起来。如果是选中,则将保存起来的规格中相同key_id的数据先删除,然后再将新的插入,如果是反选,则直接删除就好,具体的实现如下
let skuStatus = this.data.skuStatus.concat()
if (skuStatus.length > 0) {
skuStatus = skuStatus.filter((value, key, arr) => {
return value.key_id != key_id
})
}
if (select_type == "unselected") {
skuStatus.push({
"key_id": key_id,
"value_id": value_id
})
}
this.setData({
skuStatus
})
代码片段三
2、循环规格列表
保存完当前选中的规格后,再来循环代码片段二的内容(这里只是一种实现情况,按照具体情况实现具体循环),因为循环体里面的内容太多,下面给一段伪代码
外层循环{
内层value循环{
if(key_id和value_id是否在选中状态中存在)
存在,将对应的select_type设置为selected
不存在,这种情况必较复杂,单独拿出来分析
}
}
以下为不存在的情况处理办法
1、把保存的选中状态拿出来,赋值给newStatus
2、如果newStatus中包括外循环的key_id,
则先将其删除,再将循环体内的key_id和value_id添加到newStatus,这一步很重要,
let newStatus = skuStatus.concat()
newStatus = newStatus.filter((value, key, arr) => {
return value.key_id != spec.key_id
})
newStatus.push({
"key_id": spec.key_id,
"value_id": specValue.value_id
})
3、下面就将newStatus当作是已选中的状态,
把这个新的状态和可以选择的规格(代码片段一)去比较,
比较结果为true则表明这种状态可选,将对应的select_type设置为unselected,
如果为false,则表明这种状态不可选,将对应的select_type设置为locking
再来看看newStatus和代码片段一的对比过程,这里也需要采用循环
定义一个空数组skuSpecsFalg
外循环,循环代码片段一sku_list{
定义一个空数组flag
内循环,循环newStatus{
判断sku_list下面的specs是否包含内循环的key_id和value_id
存在将true添加到flag数组,不存在将false添加到flag数组并退出内层循环
}
判断flag中是否存在false,
存在将false添加到skuSpecsFalg,不存在将true添加到skuSpecsFalg中并退出整个循环
}
判断skuSpecsFalg是否包含true,包含则返回true,否则返回false
提示:下面代码中,循环体里面的return false并不会结束整个函数,只是结束当前循环
let skuSpecs2 = []
skuList.some((skuListV, skuListI, skuListA) => {
let flag = []
status.some((value, index, arr) => {
let vIndex = skuListV.specs.findIndex((v) => v.key_id == value.key_id && v.value_id == value.value_id)
if (vIndex != -1) {
flag.push(true)
} else {
flag.push(false)
return false
}
})
// console.log(flag)
if (flag.findIndex((v) => v == true) == -1) {
skuSpecs2.push(true)
return false
} else {
skuSpecs2.push(false)
}
})
if (skuSpecs2.findIndex((v) => v == true) != -1) {
return true
} else {
return false
}
这里的对比过程比较复杂,举个例子来说明一下,比如现在的newStatus如下
[
{key_id:1,value_id:44},
{key_id:3,value_id:9}
]
那么这里就应该判断的数组的两个元素是否在sku_list其中一个specs中都存在,再次强调,这里必须是其中一个specs包含数组中的两个元素,这样才可以保证这种状态是可以选中,这种规格才算是存在的。这里只要有一个specs满足这一的条件,则表明这种newStatus是可选的,如果全部specs都不满足,才表明newStatus是不可选的*