上一节拿到了对应的路径字典,现在我们需要根据所选中的进行实施更新状态了
拿到了路径字典我们还需要拿到当前选中的项,来判断搭配他的是否有库存可以进行选择
const clickSpecs = (item, val) => {
// 如果是禁用状态不作为
if (val.disabled) return false;
//如果selected为true的话说明当前项是选中的,再次点击直接取消选中就可以了
if (val.selected) {
val.selected = false;
} else {
//如果不是的话那么就把当前项目的selected 改为true,其它项改为false
item.values.forEach((bv) => {
bv.selected = false;
});
val.selected = true;
}
//每次选中的时候都要判断一下与此选中项可搭配有库存的
updateDisabledStatus(props.goods.specs, pathMap);
}
接下来来就是判断他是否再存在与路劲字段内,存在的话咋就可以进行点击选择
// 首先可以在初始化得时候更新状态是否可以点击(因为有些可能任意规格的都是没有的)
updateDisabledStatus(props.goods.specs, pathMap);
// 更新按钮的禁用状态 //这段代码里面可以有点迷,可以自己 debugger 一下
const updateDisabledStatus = (specs, pathMap) => {
// 对所有规格进行遍历
specs.forEach((spec, i) => {
// 拿到选中的规格集合
const selectedArr = getSelectedArr(specs);
// 对规格项内的选项进行遍历
spec.values.forEach((val) => {
// 已经选中的按钮不用判断
if (val.name === selectedArr[i]) return false;
// 未选中的替换对应的值 (来判断此项搭配是否可以选中,是否存有库存)
selectedArr[i] = val.name;
// 过滤无效值得undefined到key
const key = selectedArr.filter((v) => v).join(spliter);
// 设置禁用状态
val.disabled = !pathMap[key];
});
});
};
// 得到当前选中规格集合
const getSelectedArr = (specs) => {
// 先声明一个空数组,用来装入规格
const selectedArr = [];
specs.forEach((spec) => {
// 拿到当前选中项 初始化的时候,第一次进入数组内就是三个undefined
const selectedVal = spec.values.find((val) => val.selected);
// 因为后面要转为字符串去路劲字典内寻找,所有顺序不能乱,如果找到的话就添入选中项,如果没有就添入undefined
selectedArr.push(selectedVal ? selectedVal.name : undefined);
});
return selectedArr;
};
此时的话效果就已经实现了,初始化的时候就会调用一下updateDisabledStatus函数,可以直接筛选出没有库存的,变得不可点击,然后每次点击都会调用一下,那么每次点击拿到所有与其搭配的没有库存都会变的不可点击
把选中项数组传给父组件,因为我这要实时更新价格,不同的规格的价格不一样,所有我就在每次点击选项规格的时候加了个判断,如果选中的规格数组的长度,和商品规格数组的长度一样的话,那么就说明所有项都被选中了,就emit给父组件
const clickSpecs = (item, val) => {
// 如果是禁用状态不作为
if (val.disabled) return false;
// 1. 选中与取消选中逻辑
if (val.selected) {
val.selected = false;
} else {
item.values.forEach((bv) => {
bv.selected = false;
});
val.selected = true;
}
updateDisabledStatus(props.goods.specs, pathMap);
// 拿到当前选中的数组
const selectedArr = getSelectedArr(props.goods.specs).filter((v) => v);
// 判断当前数组的长度和商品规格的长度是否一致
if (selectedArr.length === props.goods.specs.length) {
// 如果当前长度一致说明规格选择完整,可以传入父组件做后续操作
const skuIds = pathMap[selectedArr.join(spliter)];
// 找多sku的id
const sku = props.goods.skus.find((sku) => sku.id === skuIds[0]);
// 传值
console.log("111");
emit("change", {
skuId: sku.id,
price: sku.price,
oldPrice: sku.oldPrice,
inventory: sku.inventory,
specsText: sku.specs
.reduce((p, n) => `${p} ${n.name}:${n.valueName}`, "")
.replace(" ", ""),
});
} else {
emit("change", {});
}
};
如果你还有其它需求,例如点进来默认选中那个规格,那么就可以加一段这个代码
// 初始化选中
if (props.SkuId) {
initSelectedStatus(props.goods, props.SkuId);
}
// 根据传入的skuid做默认选中
const initSelectedStatus = (goods, SkuId) => {
// 先找到id对应的sku
const sku = goods.skus.find((sku) => sku.id === SkuId);
// 遍历规格列表,因为规格里有selected是来控制是否选中的
goods.specs.forEach((item, i) => {
const val = item.values.find((val) => val.name == sku.specs[i].valueName);
val.selected = true;
});
};
这段代码没有什么大问题,但是还是有点细节需要磨一下的,因为当时我没有用这个功能,也就没有细磨,例如如果传进来的sku是没有库存的,那么你就需要在点击提交订单,或者加入购物车的时候做一些判断