商品多规格SKU的算法,VUE版本,笛卡尔积,对象去重

该篇文章是我通过查阅资料和自己思考实践后完整的写出最后效果的,先看最终的效果。

商品多规格SKU的效果

一、前提说明

        1、思维能力:想要自己完整的写出来首先需要有基本的逻辑思维,最核心的有两条,一是多规格数学理论上是怎么计算的,就是乘积的结果数。二是数据的比较。

        2、本次我开发的环境非常的简单,就是VUE2的一个页面,纯JS实现的,如果对JS不熟悉,估计很难看懂。

        3、关于商品规格的乘积的算法我推荐你去看这篇文章。如果看的吃力,烧脑,那就多看几篇。直到你真的看明白了,那就举一反三,融会贯通。该文简单的给解释清楚了原理和实现的思路,我代码里面的规格的核心算法也是按照这个思路来的。

二、实施步骤

        1、首先对规格的基础数据的设置(这里很简单),就一个属性名称,然后属性名称下面可以自己定义多个规格,比如 颜色:红色,绿色,蓝色。尺寸:大,中,小。这是基本的数据,比如:你有两个规格,且每个规格有3种属性,那么总的规格的种类数就是3x3=9种。

        最原始的系统的规格列表(这里可以是后端给的)

        2、所以只要选择了一种属性的一个规格值,则开始有规格数据生成了。这里你需要抽象出你想要的组合的数据的结构是什么样的,因为这一步操作是简单,但是跟你下一步使用笛卡尔积算具体有哪些规格的数据结果是有直接关系的。每一步都是环环相扣的。通过选择属性和名称和规格,我这里要的组合数据结构是这样的。

        前端用户选择规格名称和规格值后我想组装的数据结构

guigedata.valuelist = [
    {
        name:"颜色",
        value:[
        {
            name:"绿色",
            img:""
        },
        {
            name:"蓝色",
            img:""
        }
        ]
    },{
        name:"尺寸",
        value:[
            {
                name:"大",
                img:""
            },
            {
                name:"中",
                img:""
            },
            {
                name:"小",
                img:""
            }
        ]
    }
];

       组装上面数据的方法

guigenewArradd(name,itemobj){
			let fatherisnew = true
			let sonisnew    = true
			let indexs      = null
			this.guigedata.guigenewArr.map((item,key)=>{
				if(item.name == name){
					fatherisnew = false
					indexs      = key
					//检查
					item.value.map(item2=>{
						if(item2.name == itemobj.name){
							sonisnew = false
						}
					})
				}
			});
			
			if(fatherisnew){
				let pushtem  = {
					name:name,
					value:[itemobj]
				};
				this.guigedata.guigenewArr.push(pushtem);
			}
			if(sonisnew&&!fatherisnew){
				this.guigedata.guigenewArr[indexs].value.push(itemobj)
			}
		},

        3、通过上一步组合的数据,利用笛卡尔积算法获得最终可以获得的规格组合(这是核心,实现这一步获得到了,才能进行数据的组装和判断)。方法如下

        

//所有的组合往products里面生成了
		allguigeaddtoproducts(allguige){
				 let that = this
				 allguige.map((item,key)=>{
					 let products_basemodel ={...that.products_basemodel}
					 products_basemodel.guigevalue = item
					 this.allguigeaddtoproductsact( that.formDialog.products,products_basemodel);
					 
				 })
		},
		allguigeaddtoproductsact( prosuctsobj,products_basemodel){
			//这里首选的一个基本思路是 要么修改现在的数据,要么增加数据
			// prosuctsobj.push(products_basemodel)
			if(prosuctsobj.length == 0 ||(prosuctsobj.length>0 && prosuctsobj[0].guigevalue.length == 0)){
				prosuctsobj[0].guigevalue=products_basemodel.guigevalue
			}else{
				//存在有规格的数据了
				// 首先判断是变更还是增加
				//1、变更的情况,原本存在规格,只是新的在原来的基础上,多了一个规格而已。这就是变更
				// let addnew = true;
				let real_quanju_chongfu = false
				let add_or_edit  = null 
				let edit_index   = null
				prosuctsobj.map((item,index)=>{
					if(item.guigevalue.length == products_basemodel.guigevalue.length && item.guigevalue.length>0){			
						//console.log("从这里走")
						// add_or_edit = "add"
						//如果长度一样,那么就看值有没有重复的,如果最后没得重复的,那就最后增加
						let tem_all_result = [];
						for (let i = 0;i<products_basemodel.guigevalue.length;i++) {
							let newObj     = products_basemodel.guigevalue[i]
							let tem_result = item.guigevalue.some((obj) => obj.name === newObj.name && obj.value === newObj.value);
							tem_all_result.push(tem_result);
						}
						let alltrue = tem_all_result.every((value) => value === true)
						if(tem_all_result.length > 0 && alltrue ){
							//那就证明真的重复了
							real_quanju_chongfu = true
						}
					}
					//第一步只是数量上是否一致
					if((item.guigevalue.length + 1) ==  products_basemodel.guigevalue.length){
						//要要变更的数据
						//这里就是选 老数据完全在新数据里面存在的
						let tem_all_result = [];
						for(let i=0;i<item.guigevalue.length;i++){
							let newObj = item.guigevalue[i]
							let tem_result = products_basemodel.guigevalue.some((obj) => obj.name === newObj.name && obj.value === newObj.value);
							tem_all_result.push(tem_result)
						}
						let alltrue = tem_all_result.every((value) => value === true)
						if(tem_all_result.length > 0 && alltrue ){
							//找到这个家伙了,他全都是重复的
							add_or_edit = "edit"
							edit_index  = index
						}
					}
				})
				//全局重复啥也不用管
				if(real_quanju_chongfu){
					//pass
				}else{
					//检查是不是需要更新 不需要就增加
					if(add_or_edit == 'edit' && edit_index != null){
						//那就更新吧
						prosuctsobj[edit_index].guigevalue = products_basemodel.guigevalue
					}else{
						//那就增加新的
						prosuctsobj.push(products_basemodel)
					}
				}
			}
			
		},

        4、把获得的组合往最终的产品属性规格数组中添加数据,这一步看起来简单,实际是需要计算,有点复杂,但是简单一句话就是:你需要判断你上一步获得的规格到底是应该在原本的规格上进行修改,还是增加一个新的之前数据里没有存在的规格。举例,比如你之前选择了大中小三种规格,但是当你再增加一个颜色,比如红色,这时候其实还是只有三种规格,因为你只加了一个颜色进去,所以理论上你的规格组合就是[大,红色],[中,红色],[小,红色],用户有可能之前已经设置了大的库存是100,那么你增加新的规格进去的时候,就只能是往规格里面增加一个颜色的属性,值是红色,而不能直接覆盖掉原本的所有数据。所以这里的就需要对每一个数据进行循环的遍历。我这里实现的思路是,拿每一个新组合的规格,去循环遍历已经存在的规格,每一个都去进行比较。但是这里的比较其实只有三种结果,一是我的新的规格在我原本的产品属性规格中已经存在不需要任何的处理。二是,我原本的某一个产品规格属性他所有的值在我新的规格中已经存在且属性总量+1的话等于当前的我组合的规格数量,这样我就判断是需要增加了。三是,既不是一和二的,那就是需要新增规格的。这里的思维有点复杂,我写代码之前我都觉得我没有想明白,我是写的过程中,才不断的想明白的。核心就是我判断一个新的规格在我老的数据里面,到底应该是修改,还是新增,还是啥也不干(判断重复)。我最开始也是不知道到底应该怎么写逻辑判断,写着写着就想明白了(这也印证了一个道理,很多事情,你不去做,光坐着想,全都是问题,只有去做了,才能找到出路,不做光想是不行的,只要想通了七八成,就去干)。

  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个React组件的代码实现,用于实现前端SKU算法商品规格选择功能: ```jsx import React, { useState, useEffect } from "react"; const SKUSelector = ({ skuList }) => { const [selectedValues, setSelectedValues] = useState({}); const [availableOptions, setAvailableOptions] = useState({}); useEffect(() => { // 初始化可选项列表 let options = {}; skuList.forEach((sku) => { sku.attributes.forEach((attr) => { if (!options[attr.name]) { options[attr.name] = [attr.value]; } else if (!options[attr.name].includes(attr.value)) { options[attr.name].push(attr.value); } }); }); setAvailableOptions(options); }, [skuList]); const handleValueChange = (name, value) => { // 更新已选项列表 setSelectedValues({ ...selectedValues, [name]: value }); // 根据已选项列表筛选可选项列表 let options = { ...availableOptions }; for (let attrName in selectedValues) { if (attrName !== name) { skuList.forEach((sku) => { if ( sku.attributes.find((attr) => attr.name === attrName)?.value !== selectedValues[attrName] ) { options[attrName] = options[attrName].filter( (option) => option !== selectedValues[attrName] ); } }); } } setAvailableOptions(options); }; const getAvailableValues = (name) => { // 获取指定规格属性的可选项列表 return availableOptions[name] || []; }; const getSelectedSKU = () => { // 根据已选项列表获取SKU信息 let selectedSKU = null; skuList.forEach((sku) => { let matches = true; sku.attributes.forEach((attr) => { if (selectedValues[attr.name] !== attr.value) { matches = false; } }); if (matches) { selectedSKU = sku; } }); return selectedSKU; }; return ( <div> {skuList.length > 0 ? ( skuList[0].attributes.map((attr) => ( <div key={attr.name}> <label>{attr.name}:</label> <select value={selectedValues[attr.name] || ""} onChange={(e) => handleValueChange(attr.name, e.target.value)} > <option value="">请选择</option> {getAvailableValues(attr.name).map((option) => ( <option key={option} value={option}> {option} </option> ))} </select> </div> )) ) : ( <div>暂无商品信息</div> )} {getSelectedSKU() ? ( <div> <p>已选规格:{JSON.stringify(selectedValues)}</p> <p>剩余库存:{getSelectedSKU().stock}</p> </div> ) : ( <div>请选择完整规格属性</div> )} </div> ); }; export default SKUSelector; ``` 该组件接受一个SKU列表作为props,每个SKU包含一个属性列表和一个库存数量。在组件中,首先使用useEffect钩子初始化可选项列表,然后使用useState钩子管理已选项列表和可选项列表的状态。 当用户选择某个规格属性值时,组件会根据已选项列表筛选可选项列表,并更新已选项列表。当用户选择所有规格属性值后,组件会根据已选项列表获取相应的SKU信息,并显示剩余库存量。 该组件仅为示例代码,具体实现方式可能因业务需求而异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值