php商品规格sku,SKU商品规格选择
SKU商品规格选择
在线demo地址
Github代码地址
可选属性实现思路
当用户点击某选项(如"黑色")时,拿到此时所有规格的选项( { color: "黑色" })
根据商品数据、用户当前选择规格,查找匹配商品。如果找到了,就返回商品标识(商品为数组则返回数组索引 index);如果没找到,则返回 undefined 。(this.find(option))
拿到所有支持的商品的选项(如["iPhone X", "iPhone XS", "黑色", "64g"]),这些就是此时可点击的选项(要注意去重)。
可发现,同级的选项在商品的规格选项中不存在(如上面的例子中按道理来说"白色"选项也应该可点击),所以要特殊处理这种情况。可通过遍历当前用户的所有规格选项,有值的(不为null)的规格改为其他选项再去求。(如 { color: "黑色" } 改为 { color: "白色" } 去求支持的商品的所有属于“颜色”这个规格的选项)
根据刚得到的结果来修改可被点击选项的状态,不包含的选项就是不可被点击的。
Goods 类的相关说明
生成实例需要传入商品对象数组
key: string 为 商品规格名称,value: [string] 为该商品此规格的值。如:
const goods = [
{
// "商品规格名称": "该商品此规格的值",
name: "iPhone X",
color: "黑色",
storage: "64g",
},
{
color: "黑色",
name: "iPhone XS",
storage: "64g",
},
{
color: "白色",
name: "iPhone X",
storage: "64g",
},
{
color: "白色",
name: "iPhone X",
storage: "256g",
},
];
this.list
返回商品实例的数据。
[
{
name: "iPhone X",
color: "黑色",
storage: "64g",
},
{
color: "黑色",
name: "iPhone XS",
storage: "64g",
},
{
color: "白色",
name: "iPhone X",
storage: "64g",
},
{
color: "白色",
name: "iPhone X",
storage: "256g",
},
];
this.attrKey
根据商品数据,可获得由所有商品的规格 key 组成的数组。
["name", "color", "storage"];
this.attr
根据商品数据,可获得商品全部属性选项对象。
{
"name": [
"iPhone X",
"iPhone XS"
],
"color": [
"黑色",
"白色"
],
"storage": [
"64g",
"256g"
]
}
this.have(option)
判断有没有这个规格 option 的商品,返回布尔值。
const goods = [
{
// "商品规格名称": "该商品此规格的值",
name: "iPhone X",
color: "黑色",
storage: "64g",
},
{
color: "黑色",
name: "iPhone XS",
storage: "64g",
},
{
color: "白色",
name: "iPhone X",
storage: "64g",
},
{
color: "白色",
name: "iPhone X",
storage: "256g",
},
];
const example = new Goods(goods);
const option1 = { name: "iPhone X", color: "黑色", storage: "64g" };
const option2 = { name: "iPhone X", color: "黑色", storage: "128g" };
//
example.have(option1); // true
example.have(option2); // false
this.find(option)
查找匹配商品。如果找到了,就返回商品标识(商品为数组则返回数组索引 index);如果没找到,则返回 undefined 。
example.find({ name: "iPhone X", color: "黑色", storage: "64g" }); // 0
example.find({ name: "iPhone X", color: "黑色", storage: "128g" }); // undefined
adaptedAttr
判断属性可用性。
const adaptedAttr = example.adaptedAttr({ name: "iPhone X", color: "黑色" });
// {
// "name": [
// "iPhone X",
// "iPhone XS"
// ],
// "color": [
// "黑色",
// "白色"
// ],
// "storage": [
// "64g"
// ]
// }
this.combine(...chunks)
排列组合函数。
this.allOptions()
根据商品的规格,来推测用户选择的所有规格组合。
this.result
提前计算好所有规格组合对应的可被点击的选项。
this.getAdaptedAttrByResult(option)
根据 option 快速获取已经提前计算好的对应的可用属性。
完整代码
1. Goods 类
// 商品类
const Goods = class Goods {
constructor(goods) {
// 商品列表数据
this.list = goods;
// 由所有商品的规格 key 组成的数组
this.attrKey = (() => {
const result = new Set();
for (let item of goods) {
Object.keys(item).forEach((attr) => {
result.add(attr);
});
}
return Array.from(result);
})();
// 商品全部属性选项对象。此对象的成员的 key 为某规格的 key,value 为 这规格的所有选项数组。
this.attr = (() => {
const result = {};
for (let item of goods) {
const keys = Object.keys(item);
for (let key of keys) {
if (!result[key]) {
result[key] = [];
}
const value = item[key];
if (!result[key].includes(value)) {
result[key].push(value);
}
}
}
return result;
})();
// 根据商品预测所有选项组合,从而得到所有组合对应的结果
this.result = (() => {
const result = {};
const all = this.allOptions();
for (let item of all) {
const key = Object.values(item).join("--");
result[key] = this.adaptedAttr(item);
}
return result;
})();
}
have(option) {
if (Object.prototype.toString.call(option) !== "[object Object]") {
return undefined;
}
const index = this.list.findIndex((item) => {
for (let key in option) {
if (option[key] !== item[key]) {
return false;
}
}
return true;
});
const result = index !== -1;
return result;
}
find(option) {
if (Object.prototype.toString.call(option) !== "[object Object]") {
return undefined;
}
const result = [];
this.list.forEach((item, index) => {
const keys = Object.keys(option);
const isEqual = keys.every((key) => {
return option[key] === item[key];
});
if (isEqual) {
result.push(index);
}
});
return result;
}
adaptedAttr(option) {
const list = this.list;
const result = {};
for (let key of this.attrKey) {
result[key] = [];
}
// 找到符合该选项规格的商品下标
const indexArr = this.find(option);
indexArr.forEach((index) => {
for (let key in list[index]) {
const value = list[index][key];
if (!result[key].includes(value)) {
result[key].push(value);
}
}
});
// 与已选的统一规则的要特殊处理
for (let key in option) {
const tempOption = { ...option };
const otherOption = this.attr[key].filter(
(item) => item !== tempOption[key]
);
for (let item of otherOption) {
tempOption[key] = item;
if (this.find(tempOption).length > 0) {
result[key].push(item);
}
}
}
return result;
}
combine(...chunks) {
const res = [];
const helper = function (chunkIndex, prev) {
const chunk = chunks[chunkIndex];
const isLast = chunkIndex === chunks.length - 1;
for (let val of chunk) {
const cur = prev.concat(val);
if (isLast) {
res.push(cur);
} else {
helper(chunkIndex + 1, cur);
}
}
};
helper(0, []);
return res;
}
allOptions() {
const options = [];
const optionsKey = [];
for (let key in this.attr) {
options.push(this.attr[key].concat(null));
optionsKey.push(key);
}
const result = this.combine(...options).map((item, index) => {
const obj = {};
item.forEach((option, optionIndex) => {
if (!!option) {
obj[optionsKey[optionIndex]] = option;
}
});
return obj;
});
return result;
}
getAdaptedAttrByResult(option) {
const sortOption = [];
// 排序
this.attrKey.forEach((item) => {
if (option[item]) {
sortOption.push(option[item]);
}
});
return this.result[sortOption.join("--")];
}
};
2. 商品数据
// 现有商品
const goods = [
{
id: 1,
options: {
name: "iPhone X",
color: "黑色",
storage: "64g",
},
},
{
id: 2,
options: {
name: "iPhone XS",
color: "黑色",
storage: "64g",
},
},
{
id: 3,
options: {
name: "iPhone X",
color: "白色",
storage: "64g",
},
},
{
id: 4,
options: {
name: "iPhone X",
color: "白色",
storage: "256g",
},
},
];
3. 动态样式
// 样式们
const disabledStyle = {
margin: "0 20px",
padding: "5px 10px",
color: "rgba(0,0,0,.25)",
background: "#f5f5f5",
border: "1px solid",
borderColor: "#d9d9d9",
};
const normalStyle = {
margin: "0 20px",
padding: "5px 10px",
color: "rgba(0,0,0,.85)",
background: "#fff",
border: "1px solid",
borderColor: "#d9d9d9",
};
const selectedStyle = {
margin: "0 20px",
padding: "5px 10px",
color: "#fff",
background: "#1890ff",
border: "1px solid",
borderColor: "#1890ff",
};
4. 渲染相关代码
import React, { useState, useMemo } from "react";
const zh = {
name: "型号",
color: "颜色",
storage: "内存",
};
const example = new Goods(goods.map((item) => item.options));
const { attr, attrKey } = example;
function App() {
// 渲染的选择规格数据
const renderGoods = attrKey.map((key) => {
if (key === "storage") {
return {
label: key,
list: ["64g", "128g", "256g"],
};
}
return {
label: key,
list: attr[key],
};
});
// 当前选中的数据
const [selected, setSelected] = useState({});
// 可被选的数据
const adaptedOption = useMemo(() => {
return example.getAdaptedAttrByResult(selected);
}, [selected]);
// 选项的状态
const optionStatus = useMemo(() => {
const result = {};
renderGoods.forEach((item) => {
const key = item.label;
const list = item.list;
result[key] = {};
list.forEach((option) => {
result[key][option] = -1;
if (adaptedOption[key].includes(option)) {
result[key][option] = 0;
}
});
});
return result;
}, [adaptedOption, renderGoods]);
function onClick(value, optionKey) {
// 禁用不可点
if (!optionStatus[optionKey] || optionStatus[optionKey][value] === -1) {
return;
}
const tempSelected = { ...selected };
// 是否是取消
if (tempSelected[optionKey] === value) {
delete tempSelected[optionKey];
} else {
tempSelected[optionKey] = value;
}
setSelected(tempSelected);
}
return (
{renderGoods.map((options, index) => (
{zh[options.label]}
{options.list.map((item, itemIdx) => (
key={itemIdx}
onClick={() => onClick(item, options.label)}
style={
optionStatus[options.label][item] === -1
? disabledStyle
: selected[options.label] === item
? selectedStyle
: normalStyle
}
>
{item}
))}
))}
);
}
export default App;
php商品规格sku,SKU商品规格选择相关推荐
- uniapp商品详情页规格、SKU选择
uniapp商品详情页购物车选择 提示:这里因为后台返回的数据格式原因,代码性能可能有点稍差,但是注释是很完整的 文章目录 uniapp商品详情页购物车选择 先上代码,以示诚意 后台接口返回的数据格式 ...
- 电商系统,剖析商品模块中商品表(spu)、规格表(sku)的数据库是如何设计的
不管开发B2C.B2B2C.还是B2B等电商项目,不可避免的要实现上面的详情页面.页面展示中,商品的名称.商品的主图.商品的详情都容易搞定.就是商品种类繁多后,每一种商品具有不同的规格,不同的规格就会 ...
- 关于商品规格(SKU)的设置
2019独角兽企业重金招聘Python工程师标准>>> SKU定义和正确发布 SKU=stock keeping unit(库存量单位),SKU即库存进出计量的单位, 可以是以件.盒 ...
- mysql商品规格设计_关于商品规格(SKU)的设置
SKU定义和正确发布 SKU=stock keeping unit(库存量单位),SKU即库存进出计量的单位, 可以是以件.盒.托盘等为单位.在服装.鞋类商品中使用最多最普遍. 例如纺织品中一个SKU ...
- 多规格的商品选择不同的规格值影响其他规格使之不可选
比如说现在一个SPU下对应有三种类型规格,分别为颜色,尺寸,重量 三种类型规格各自拥有三个规格值 颜色: 红色,白色,蓝色 尺寸: XL XXL XXXL 重量: 50kg 100kg 150 ...
- sku展示php,前端如何展示商品属性:SKU多维属性状态判断算法的应用
作者 | 周琪力 编辑 | 尾尾 本文为前端之巅周琪力原创,未经作者许可禁止转载. 问题描述 这个问题来源于选择商品属性的场景.比如我们买衣服.鞋子这类物件,一般都需要我们选择合适的颜色.尺码等属性 ...
- 电商商品列表应以SPU还是SKU展示商品?
我们先了解下,SPU和SKU的概念,方便大家跟上思路,如下: SPU(Standard Product Unit):标准化产品单元.是商品信息聚合的最小单位,是一组可复用.易检索的标准化信息的集合,该 ...
- 【精品】电商项目 中 基于SPU与SKU的 商品 数据库表设计
简介 一般情况下我们使用5张表就可以解决基本的需求了: 商品分类表:category 商品表(即SPU表):表:product 商品规格表(即sku表):product_specs 属性key表:at ...
- mysql 商品规格表_商品规格分析
产品表每次更新商品都会变动的,ID不能用,可是购物车还是用了,这就导致每次保存商品,哪怕什么都没有改动,也会导致用户的购物车失效. ~~~ 其实可以考虑不是每次更新商品就除所有的SKU,毕竟有时什么都 ...
最新文章
- laravel5.5 不能正常自动回复的问题
- python课后题答案第五章_Python语言程序设计(美-梁勇)第5章习题解答
- Bengio实验室推出开源AI药物研发平台,唐建领队、清北上交学生参与开发
- R语言与Tableau集成之可视化应用
- Spring Cloud Alibaba - 18 Nacos Config配置中心加载相同微服务的不同环境下的通用配置
- Python中常用的内置函数(不断更新中)
- php 函数 打印,php打印函数入门教程
- 物联网设备的互操作性问题探讨
- 坐标轨迹计算_机器人的轨迹规划与自动导引
- 涤纶针织物用分散染料染色时,为什么小样与大样不符?
- 棋牌游戏-c#实现批量修改文件后缀
- c++的内存问题---内存碎片
- 谷歌网页存储为pdf或图片
- Perfectly Clear Complete V3 mac(ps/lr智能修图插件)破解版
- 公司部门英文缩写简称收集
- CyanogenMod 7
- 赛码网在线考试无法使用外接摄像头解决方案
- 第十讲:Python爬取网页图片并保存到本地,包含次层页面
- 长篇幅详解辐射定标、大气校正、监督分类、掩膜统计、植被覆盖度操作
- 神了,阿里数据库专家纯手写了这份604页的Oracle+MySQL攻坚指南