React 版 sku商品规格选择器和sku生成器

演示地址:https://tccsg.github.io/react-sku/
仓库地址:https://github.com/tccsg/react-sku

通用版仓库地址:https://github.com/tccsg/ct-sku

因为业务的需求不得不对sku进行深入的研究,在还没写代码之前感觉是简单的,一天就搞定了

结果几天过后…

甚至想打人了,在想当初是谁给我的自信。还好最后还是写出来了,差点误了进度。

仓库的版本是针对普通的 react hook结合ant版的
因为我是用React-Native写的App也是用hook写的比较好迁移
小程序方面用的是Taro这个框架,不过是用class方式写的,迁移起来稍微麻烦🤏,不过问题不大。

#####代码解析(sku选择器)
代码方面重点解析sku选择器。
sku格式

/**
   * 通过skus初始化 各个规格
   */
  const setDrawOptions = () => {
    const skus = data?.skus
    const _spec = data?.spec
    const dataExtraHold = data.skuHold
    let _tags: Spec = {}
    let _maxPrice = data?.minPrice ?? 0
    // 用于初始化默认选项
    if (_spec) {
      _tags = _spec
      setSkuHold(dataExtraHold as number)
    } else {
      const _tempTagsStrArray: any = {} // 临时字符串数组
      let _skuHold = 0 // 用于计算总库存
      skus?.forEach((s) => {
        _skuHold += s.hold
        s?.properties?.forEach((p) => {
          if (!_tags[p.name]) {
            _tags[p.name] = []
            _tempTagsStrArray[p.name] = []
          }

          if (!_tempTagsStrArray[p.name].includes(p.value)) {
            _tempTagsStrArray[p.name].push(p.value)
            _tags[p.name].push({
              value: p.value,
              disable: false,
              select: false
            })
          }
        })
        if (s.price > _maxPrice) {
          _maxPrice = s.price
        }
      })
      setSkuHold(_skuHold)
      TotalSkuHold = _skuHold
    }
    let _canFlag = !data.canFlag ? false : true
    /**  */
    if (skus?.length === 1 && !skus[0].properties?.length && skus[0].hold <= 0) {
      _canFlag = false
    }
    setCanFlag(_canFlag)
    setProdPrice(data?.minPrice ?? 0)
    setMaxPrice(_maxPrice)
    setSpecDisable(_tags)
  }

初始化各个选项用的,把sku的格式转成以下格式

{
  颜色:[
    {
        value: '红色',
        disable: fasle,   // 是否可点击
        select: false // 是否选中
    },
   //.....
  ]
  容量:[
    {
        value: '16G',
        disable: fasle,   // 是否可点击
        select: false // 是否选中
    },
// .....
  ]
}
/** 用于规格都没选中的时候 设置 规格是否可以点击,该路径上如果跟该属性的组合没库存则该属性不能点击 */
  // 可合并在 skuCore中
  const setSpecDisable = (tags: any) => {
    const { skus } = data
    Object.keys(tags).forEach((sk) => {
      tags[sk].forEach((sv: SpecItem) => {

        const currentSpec = `${sk}:${sv.value}`
        // 找到含有该规格的路径下 库存不为0的 sku
        const querySku = skus.find((sku) => {
          const queryProperty = sku.properties.find(sp => `${sp.name}:${sp.value}` === currentSpec)
          return queryProperty && sku.hold
        })
        // 如果找到 对应该属性的路径 sku有不为0 的则可选
        sv.disable = !querySku
      })
    })
    setSpec({ ...tags })
  }

这个是用于在规格都没选中的判断哪些不能点,因为是早起版本留下来的,也不敢动,应该是可以合并到下面的会提到的skuCore中。

 /** 规格选项点击事件 */
  const onPressSpecOption = (k: string, currentSpectValue: any) => {
    let isCancel = false
    setCount(1)
    // 找到在全部属性spec中对应的属性
    const currentSpects = spec[Object.keys(spec).find((sk) => sk === k) || ''] || []
    // 上一个被选中的的属性
    const prevSelectedSpectValue: any = currentSpects.find((cspec) => cspec.select) || {}
    // 设置前一个被选中的值为未选中
    prevSelectedSpectValue.select = false
    // 只有当当前点击的属性值不等于上一个点击的属性值时候设置为选中状态
    if (prevSelectedSpectValue === currentSpectValue) {
      isCancel = true
    } else {
      // 设置当前点击的状态为选中
      currentSpectValue.select = true
    }

    // 全部有选中的规格数组 ##可优化
    const selectedSpec = Object.keys(spec)
      .filter((sk: string) => spec[sk].find((sv) => sv.select))
      .reduce((prev: string[], currentSpecKey) => {
        return [...prev, `${currentSpecKey}:${spec[currentSpecKey].find((__v) => __v.select)?.value}`]
      }, [])
    if (isCancel) {
      // 如果是取消且全部没选中
      if (!selectedSpec.length) {
        // 初始化是否可点
        setSpecDisable(spec)
      }
    }
    // 如果规格中有选中的 则对整个规格就行 库存判断 是否可点
    if (selectedSpec.length) {
      skuCore(selectedSpec, k)
    }

    let price = null
    if (selectedSpec.length) {
      price = getSkuInfoByKey(spec, 'price')
    } else {
      price = data?.minPrice
    }
    const hold = getSkuInfoByKey(spec, 'hold') ?? TotalSkuHold
    setSpec({ ...spec })
    if (price) {
      setProdPrice(price)
    }
    setSkuHold(hold)
    optionsChange && optionsChange(spec)
  }

代码也都有注释这里就不做解释了。

/**
   * 核心代码
   * @param selectedSpec 已选中的数组
   * @param currentSpecName 当前点击的规格的名称
   */
  const skuCore = (selectedSpec: string[], currentSpecName?: string) => {
    const { skus } = data
    Object.keys(spec).forEach((sk: string) => {
      if (sk !== currentSpecName) {
        // 找出该规格中选中的值
        const currentSpecSelectedValue = spec[Object.keys(spec).find((_sk) => sk === _sk) || ''].find((sv) => sv.select)
        spec[sk].forEach((sv: SpecItem) => {
          // 判断当前的规格的值是否是选中的,如果是选中的 就不要判断是否可以点击直接跳过循环
          if (!sv.select) {
            const _ssTemp = [...selectedSpec]
            // 如果当前规格有选中的值
            if (!!currentSpecSelectedValue) {
              const sIndex = _ssTemp.findIndex((_sv) => _sv === `${sk}:${currentSpecSelectedValue.value}`)
              _ssTemp.splice(sIndex, 1)
            }
            _ssTemp.push(`${sk}:${sv.value}`)
            const _tmpPath: SkuItem[] = []
            // 找到包含该路径的全部sku
            skus.forEach((sku: SkuItem) => {
              // 找出skus里面包含目前所选中的规格的路径的数组的数量
              const querSkus = _ssTemp.filter((_sst: string) => {
                const querySpec = sku.properties.some((p) => {
                  return `${p.name}:${p.value}` === _sst
                })
                return querySpec
              })
              const i = querSkus.length
              if (i === _ssTemp.length) {
                _tmpPath.push(sku) // 把包含该路径的sku全部放到一个数组里
              }
            })
            const hasHoldPath = _tmpPath.find((p) => p.hold) // 判断里面是要有个sku不为0 则可点击
            let isNotEmpty = hasHoldPath ? hasHoldPath.hold : 0
            sv.disable = !isNotEmpty
          }
        })
      }
    })
    judgeCanAdd(skus)
  }

这个就是用来判断,当我们点击一个规格值后,除了当前规格的所有值其他规格选中值以外的值都要判断是否可点,这些值要跟当前所选中的规格值组合成一个路径,然后从skus中找到包含当前路径的所有sku,然后通过判断这些sku中是否含有非0的库存则说明这个规格值可以点。

/**
   * 
   * @param _spec 规格属性
   * @param sk 该sku下的 sk这个key的值
   * 
   * 不传sk的话返回所有信息
   */
  const getSkuInfoByKey = (_spec: Spec, sk?: string) => {
    // 已选的规格:[{ name:规格名称, value:已选规格内容 }]
    const selectedSpec: { name: string, value: string }[] = []

    Object.keys(_spec).forEach((k) => {
      const selectedValue = _spec[k].find((sv) => sv.select)
      if (selectedValue) {
        // 这块部分也可以在选择的时候直接处理
        selectedSpec.push({
          name: k,
          value: selectedValue.value
        }) 
      }
    })
    // 在规格没有全选的情况下 不执行查询操作
    if (selectedSpec.length !== Object.keys(_spec).length) {
      return
    }
    const { skus } = data
    const querySku = skus.find((sku) => {
      // 对比两个数组找到 两个都不存在的sku 如果为0 则说明完全匹配就是该sku
      const diffSkus = _.xorWith(selectedSpec, sku.properties, _.isEqual)
      return !diffSkus.length
    })
    if (querySku && querySku[sk ?? '']) {
      return querySku[sk ?? '']
    } else if (querySku) {
      return querySku
    } else {
      return null
    }
  }

用于当全部规格值都选中的时候,找到含这个路径的sku,就可以知道库存和价格了,也可以单独获取价格或者库存等的这些信息。

好了当我知道可以用的时候我是

演示图片

演示图片

演示地址:https://tccsg.github.io/react-sku/
仓库地址:https://github.com/tccsg/react-sku

万物论
关注 关注
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习笔记:SKU组件(React)
qq_24724109的博客
03-16 3535
SKU组件(React) 源码 起因 今天看掘金的时候看到前端SKU算法实现,因为公司也有涉及到SKU的业务,记录一下自己写SKU的一个例子吧,刚好他有提供后端的API接口数据,mock一下干起来,但是在做的时候还是有很多问题的,这里做一下记录 实现效果 mock数据 export const simulatedSku = { id: 2, title: "林间有风自营针织衫", ...
电商后台sku表格生成js
11-17
做到的一个电商项目,遇到商品上传时候中的多规格商品上传时,根据勾选的规格值生成sku表格(规格表格),用的jQuery,上传的是整个商品上传的js文件
Zent - 源自有赞微商城的 React 组件
weixin_33735077的博客
11-10 453
Zent ( ˈzent ) 是有赞 PC 端 Web UI 规范的 React 实现本,提供了一整套基础的 UI 组件以及常用的__业务组件__。通过 Zent,可以快速搭建出风格统一的页面,提升开发效率。目前我们有 45+ 组件,其中包括 Design 以及 SKU 等实用的业务组件。这些组件都已经在有赞的各类 PC 业务中广泛使用...
推荐开源项目:Sku - Android商品规格选择器
gitblog_00031的博客
05-20 363
推荐开源项目:Sku - Android商品规格选择器 项目地址:https://gitcode.com/wuhenzhizao/android-sku 项目介绍 在电商应用开发中,商品详情页的商品规格选择是一个常见的需求,而Sku正是为此设计的一个高效且易于集成的开源库。它模拟了淘宝、天猫、京东等大型电商平台的多维度属性选择机制,并提供了流畅的购物车动画效果。该项目不仅兼容传统的MVP模式,还支...
React+antd 实现sku商品规格功能
m0_65629667的博客
05-28 982
如果还是没有解决你的问题可以拉取我的github源码// ---------变量------------// 显示的数据数量//规格名//规格值// 规格展示数据// 规格sku// ---------方法函数------------} else {message.error('请输入规格名称');//添加规格值if (specValue) { // 规格值// 如果有一样的规格名称就push到老的规格值里面tableSKU();} else {
【工具】批量SKU生成器
最新发布
大白菜啊
06-06 191
工具支持批量生成SKU,支持自定义配置项,可以生成各种不同的SKU
SKU编号生产
jq1223的博客
03-23 232
效果: String format = DateFormatUtils.format(new Date(), "yyyyMMdd"); String format1 = String.format("%06d", 22); String format2 = String.format("%03d", 1); skuStock.setSkuCode(StringUtils.join(format,format1,
【VK】商品规格SKU选择器组件豪华(uniapp,可编译成H5、APP、各大小程序)
wwqwwq112的博客
09-27 3398
【VK】【开箱即用】商品sku选择器组件豪华独立,支持多种皮肤。
vue3+Ts+Hook的方式实现商城核心功能sku选择器
专注java二开部署
01-06 1539
Hooks并不是VUE特有的概念,实际上它原本被用于指代一些特定时间点会触发的勾子。而在React16之后,它被赋予了新的意义:一系列以 use 作为开头的方法,它们提供了让你可以完全避开 class式写法,在函数式组件中完成生命周期、状态管理、逻辑复用等几乎全部组件开发工作的能力在VUE3中,Hooks的概念结合了VUE的响应式系统,被称为组合函数。
react-sku:react实现商品sku选择效果
05-13
代码解析(sku 选择器)代码方面重点解析 sku 选择器。/** * 通过skus初始化 各个规格 */ const setDrawOptions = () => { const skus = data?.skus const _spec = data?.spec const dataExtraHold =
sku-algorithm:商品规格选择-sku算法
05-08
如果有解决思路的同学,请给我提PR:handshake::handshake::handshake:商品规格选择-前端 sku 算法相信大家看到这张图片就知道我们这篇文章要讲什么了,没错就是-商品规格选择的解法。近来在掘金上面看见大家都在...
jQuery仿制淘宝商品发布动态生成SKU表格实例代码.zip
07-11
代码片段:   <div class="gallery-cell">     <img />   </div>   <div class="gallery-cell">     <img />   </div>   <div class="gallery-cell">     <img />   </div>
Android Sku属性选择器
05-06
Android Sku选择器, 类似于淘宝,天猫,京东,支持多维属性,购物车动画,支持MVVM架构,可以直接使用
react-react日期选择器
08-15
react日期选择器 it works better on mobile terminal
SkuGenerator-React
05-08
该软件包括基于sku和mpn的产品,库存和市场(Shopify,Etsy,eBay,Amazon)管理。 将Laravel用作后端,将React用作前端,并将AWS RDS用作数据库。 这是该项目的前端。将项目构建到后端npm运行构建
react-GradientLab是一款采用React制作的渐变色选择器
08-15
GradientLab是一款采用React制作的渐变选择器,旨在让您快速直观地选择漂亮的渐变色。
B2C电子商务系统研发——商品SKU分析和设计(二)
颜超敏的电子商务博客
02-06 9116
上文谈到5种商品SKU设计模式,本文将做些细化说明。   笔者研究过不少电子商务平台软件,关于SKU的设计各有不同,之所以有这样的区别,是因为面向不同规模的电子商务网站, 存在产品分类复杂度,产品数量级的差异。一种设计方式对于百货式的网站,如京东、淘宝等,也许比较方便,但也许对于一个 专卖服装的小型时尚类网站就不够方便了。 我们先看一下麦包包的     女包:http://item.
商品规格可选怎么设计_分分钟学会前端sku算法(商品规格选择)
weixin_39540725的博客
11-11 3455
相信大家看到这张图片就知道我们这篇文章要讲什么了,没错就是-商品规格选择的解法。近来在掘金上面看见大家都在研究“商品规格选择”的问题,例如晨曦大佬的前端电商 sku 的全排列算法很难吗?学会这个套路,彻底掌握排列组合。 在这篇文章里面,大佬写明了如何实现sku的全排列,思路非常的棒,但是并没有紧贴业务场景。真正的业务场景是,我们要根据用户每一次选择的规格,找出剩下可选的规格和不可选的规格,表现...
[前端框架]React
qq_31123547的博客
06-08 771
学习资料 1 阮一峰 2 官方文档 3 汇智网这里写链接内容 4 土豆视频 5 API感觉react的原理完全混乱了之前所谓“结构 行为 表现”三者分离的原则。 真是分久必合,合久必分呀 以下是练习过程中的胡言乱语,不成系统1 页面script 的 type 注意,要写为 type="text/babel"2 主要会用到 ReactDOM.render() 来进行页面搭建3 组件化v
前端sku算法(商品规格选择)react代码实现
06-01
以下是一个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信息,并显示剩余库存量。 该组件仅为示例代码,具体实现方式可能因业务需求而异。

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
5
原创
9
点赞
21
收藏
5
粉丝
关注
私信
写文章

热门文章

  • Next.js + Typescript实现React的服务端渲染,怎么简单怎么来 5096
  • 基于ElementUI封装的表头带多种筛选器的表格组件 3528
  • React 版 sku商品规格选择器和sku生成器 2518
  • 这是一个快速构建nextjs应用的工具 287
  • 为何不自己实现个 “vue-cli” 呢? 206

最新评论

  • Next.js + Typescript实现React的服务端渲染,怎么简单怎么来

    Java_AiNiYo: 行文戏谑,写的不错

您愿意向朋友推荐“博客详情页”吗?

  • 强烈不推荐
  • 不推荐
  • 一般般
  • 推荐
  • 强烈推荐
提交

最新文章

  • 这是一个快速构建nextjs应用的工具
  • Next.js + Typescript实现React的服务端渲染,怎么简单怎么来
  • 为何不自己实现个 “vue-cli” 呢?
2020年1篇
2019年4篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

PHP网站源码福田网络广告推广松岗关键词按天扣费龙岗网站推广工具东莞网站排名优化观澜企业网站建设沙井百度seo大鹏网站优化软件荷坳seo网站推广罗湖网站优化按天计费西乡企业网站改版龙华网站关键词优化福田百度网站优化排名民治网站推广工具平湖网站推广系统民治百度竞价包年推广同乐至尊标王塘坑seo排名福永百度网站优化广州模板制作大浪英文网站建设福田网站排名优化爱联百度seo平湖关键词按天收费坑梓网站排名优化民治关键词按天扣费坪地建站塘坑模板网站建设南联营销网站木棉湾百搜词包惠州网站搜索优化歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

PHP网站源码 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化