SKU组件(React版)
{label}
);
};
SKU Group: 集中管理SKU的状态,类似于RadioGroup, CheckboxGroup其实都可以模仿这种封装的思路
利用props.children获取各个子元素的ReactElement对象,之后通过cloneElement将父组件内管理状态的onChange方法进行注入(类似于HOC那种感觉),将子组件的activate和onChange方法通过父组件进行管理
封装一些其他自己要用的属性
大功告成
// 定义了Empty,这个Empty对空的时候进行设置
export const Empty = Symbol("empty");
export const SkuGroup = props => {
const { value, onChange, skuName } = props;
const [selected, setSelected] = useState(value);
const { children } = props;
const _onChange = (value, activate) => {
const _value = !activate && selected === value ? Empty : value;
setSelected(_value);
onChange?.(_value);
};
const renderGroupChild = (child, index) => {
const { props: childProps } = child;
return React.cloneElement(child, {
...childProps,
onChange: _onChange,
activate: childProps.value === selected,
key: `create-${index}`,
style: {
...(childProps?.style ?? {}),
marginLeft: index === 0 ? 0 : "20px"
}
});
};
return (
{skuName &&
);
};
SKU组件实现的思路分析
从数据来看,每个商品(SPU)中包含多个SKU,所以要将多个SKU分别提出来整理成这个样子,就是想sku进行归类
选区_059.png
点击选中某个SKU之后,将选中的SKU的id作为筛选列表中的值,我们需要遍历整个商品列表,筛选出在商品列表中所有满足筛选条件的商品
通过在满足条件的商品列表中进行遍历,得到剩下可选的sku,其余的将sku中的disabled设为true即不能被选择
// 代码中的几个关键变量
// skuList: 商品拥有的所有sku组合的型号(SPU中的所有商品类型)
// sku: 需要显示的sku card
// selectSku: radio显示选中值的[1, 2, 3]
// 初始化的时候aviableSku就是所有的商品类目
const _getSku = (aviableSku = []) => {
const _sku = {};
const _aviableSku = {};
// 得到目前可以选择的所有商品的sku
aviableSku.forEach(item => {
item.forEach(x => {
const key = JSON.stringify({ key_id: x.key_id, key: x.key });
const value = {
value_id: x.value_id,
value: x.value,
disabled: false
};
_aviableSku[key]
? _aviableSku[key].some(z => z.value_id === x.value_id)
? null
: _aviableSku[key].push(value)
: (_aviableSku[key] = [value]);
});
});
// 将SKU中所有不满足aviableSku的东西diabled掉
skuList.forEach(item => {
// 每个商品
item.forEach((x, i) => {
// 商品下的每个sku
const key = JSON.stringify({ key_id: x.key_id, key: x.key });
const value = {
value_id: x.value_id,
value: x.value,
disabled: !_aviableSku[key].some(item => item.value_id === x.value_id)
};
_sku[key]
? _sku[key].some(z => z.value_id === x.value_id)
? null
: _sku[key].push(value)
: (_sku[key] = [value]);
});
});
setMySku(_sku);
};
在选择sku的时候,我们需要确定这个sku是如何改变的,并且调整对应的aviableSku
useEffect(() => {
// 利用useRef记录上一次选择sku的状态
if (prevSku.current) {
// 找到哪一个SKU的值发生了变化
const cIndex = findChangeIndex(prevSku.current, selectSku);
if (cIndex !== -1) {
const changeValue = selectSku[cIndex];
let otherCondition = {};
const keys = Object.keys(sku);
selectSku.forEach((item, index) => {
if (
changeValue === Empty
// 改变值为Empty,说明原来选中,现在取消选中场景
? index !== cIndex && item !== Empty
// 说明Item是有限定值的
: item !== Empty
) {
// 将限定值保存在otherCondition中
// 记录现在的限定状态
const key_id = JSON.parse(keys[index])["key_id"];
otherCondition[key_id]?.push(item) ??
(otherCondition[key_id] = [item]);
}
});
// 通过限定矩阵的值挑选出满足条件的商品类别
const aviableSku = skuList.filter(good => {
const aviableGood = good.map(sku => {
const isInOther = otherCondition[sku.key_id];
return isInOther !== undefined
? isInOther.includes(sku.value_id)
: true;
});
return aviableGood.every(item => item);
});
_getSku(aviableSku);
}
} else {
_getSku(skuList);
}
prevSku.current = selectSku;
}, [selectSku]);
{skuName}
}
{children.map((child, index) => {
return child?.type === SkuCard ? renderGroupChild(child, index) : child;
})}

发表评论 (审核通过后显示评论):