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商品规格选择相关推荐

  1. uniapp商品详情页规格、SKU选择

    uniapp商品详情页购物车选择 提示:这里因为后台返回的数据格式原因,代码性能可能有点稍差,但是注释是很完整的 文章目录 uniapp商品详情页购物车选择 先上代码,以示诚意 后台接口返回的数据格式 ...

  2. 电商系统,剖析商品模块中商品表(spu)、规格表(sku)的数据库是如何设计的

    不管开发B2C.B2B2C.还是B2B等电商项目,不可避免的要实现上面的详情页面.页面展示中,商品的名称.商品的主图.商品的详情都容易搞定.就是商品种类繁多后,每一种商品具有不同的规格,不同的规格就会 ...

  3. 关于商品规格(SKU)的设置

    2019独角兽企业重金招聘Python工程师标准>>> SKU定义和正确发布 SKU=stock keeping unit(库存量单位),SKU即库存进出计量的单位, 可以是以件.盒 ...

  4. mysql商品规格设计_关于商品规格(SKU)的设置

    SKU定义和正确发布 SKU=stock keeping unit(库存量单位),SKU即库存进出计量的单位, 可以是以件.盒.托盘等为单位.在服装.鞋类商品中使用最多最普遍. 例如纺织品中一个SKU ...

  5. 多规格的商品选择不同的规格值影响其他规格使之不可选

    比如说现在一个SPU下对应有三种类型规格,分别为颜色,尺寸,重量 三种类型规格各自拥有三个规格值 颜色: 红色,白色,蓝色 尺寸: XL  XXL  XXXL 重量: 50kg  100kg  150 ...

  6. sku展示php,前端如何展示商品属性:SKU多维属性状态判断算法的应用

    作者 | 周琪力 编辑 | 尾尾 本文为前端之巅周琪力原创,未经作者许可禁止转载. 问题描述 这个问题来源于选择商品属性的场景.比如我们买衣服.鞋子这类物件,一般都需要我们选择合适的颜色.尺码等属性 ...

  7. 电商商品列表应以SPU还是SKU展示商品?

    我们先了解下,SPU和SKU的概念,方便大家跟上思路,如下: SPU(Standard Product Unit):标准化产品单元.是商品信息聚合的最小单位,是一组可复用.易检索的标准化信息的集合,该 ...

  8. 【精品】电商项目 中 基于SPU与SKU的 商品 数据库表设计

    简介 一般情况下我们使用5张表就可以解决基本的需求了: 商品分类表:category 商品表(即SPU表):表:product 商品规格表(即sku表):product_specs 属性key表:at ...

  9. mysql 商品规格表_商品规格分析

    产品表每次更新商品都会变动的,ID不能用,可是购物车还是用了,这就导致每次保存商品,哪怕什么都没有改动,也会导致用户的购物车失效. ~~~ 其实可以考虑不是每次更新商品就除所有的SKU,毕竟有时什么都 ...

最新文章

  1. laravel5.5 不能正常自动回复的问题
  2. python课后题答案第五章_Python语言程序设计(美-梁勇)第5章习题解答
  3. Bengio实验室推出开源AI药物研发平台,唐建领队、清北上交学生参与开发
  4. R语言与Tableau集成之可视化应用
  5. Spring Cloud Alibaba - 18 Nacos Config配置中心加载相同微服务的不同环境下的通用配置
  6. Python中常用的内置函数(不断更新中)
  7. php 函数 打印,php打印函数入门教程
  8. 物联网设备的互操作性问题探讨
  9. 坐标轨迹计算_机器人的轨迹规划与自动导引
  10. 涤纶针织物用分散染料染色时,为什么小样与大样不符?
  11. 棋牌游戏-c#实现批量修改文件后缀
  12. c++的内存问题---内存碎片
  13. 谷歌网页存储为pdf或图片
  14. Perfectly Clear Complete V3 mac(ps/lr智能修图插件)破解版
  15. 公司部门英文缩写简称收集
  16. CyanogenMod 7
  17. 赛码网在线考试无法使用外接摄像头解决方案
  18. 第十讲:Python爬取网页图片并保存到本地,包含次层页面
  19. 长篇幅详解辐射定标、大气校正、监督分类、掩膜统计、植被覆盖度操作
  20. 神了,阿里数据库专家纯手写了这份604页的Oracle+MySQL攻坚指南

热门文章

  1. 对话框(Dialog)
  2. excel在线_Excel太难搞?有了它帮你自动生成,制作高大上图表,用过都说好
  3. 一文读懂ABtest实验分析与实验复盘
  4. JavaScript验证码示例
  5. python求和函数sum_python求和函数sum()详解
  6. linux的vim查找的正则表达式,VIM 正则表达式搜索字符串
  7. android开发三大框架!Android开发者出路在哪?完整PDF
  8. 家电行业的寒冬中,“卖火柴的小女孩”一个接一个
  9. (转)阿德勒的三棱镜
  10. 电脑如何刻录光盘的方式