目前有一个这样的需求 类似淘宝 京东选择
但是在人家大厂给的数据我不清除是什么样子的
我这边后端给的数据 一开始是想把规格全部显示出来的 发现实现不了 后端的数据有限
因为必须选择一个颜色 才可以对应的第二个规格 才知道有没有库存
因为这个库存 是由两个规格决定的 这种的话 要想 做成京东或者淘宝那种
无库存无法显示的效果是不行的 看一下我的后端给的数据
[
{
"id": "1384947912936914944",
"image": "",
"stock": 0,
"supplyCode": "",
"sellerPrice": "8250",
"masterAttrName": "颜色",
"masterAttrValue": "紫绿色调00374",
"slaveAttrName": "参考身高",
"slaveAttrValue": "160cm"
},
{
"id": "1384947912953692160",
"image": "",
"stock": 19,
"supplyCode": "",
"sellerPrice": "8250",
"masterAttrName": "颜色",
"masterAttrValue": "紫绿色调00374",
"slaveAttrName": "参考身高",
"slaveAttrValue": "165cm"
},
{
"id": "1384947912970469376",
"image": "",
"stock": 50,
"supplyCode": "",
"sellerPrice": "8250",
"masterAttrName": "颜色",
"masterAttrValue": "红绿色调00364",
"slaveAttrName": "参考身高",
"slaveAttrValue": "160cm"
},
{
"id": "1384947912987246592",
"image": "",
"stock": 100,
"supplyCode": "",
"sellerPrice": "8250",
"masterAttrName": "颜色",
"masterAttrValue": "红绿色调00364",
"slaveAttrName": "参考身高",
"slaveAttrValue": "165cm"
}
]
这里面的数据 stock 是 0 的话 我前端自己又加了一个数据 isDisable字段 为true 无法选择
需要把这个数据整体更换成 这样的就好了
[
{
"value": "紫绿色调00374",
"disabled": false,
"heights": [
{
"value": "160cm",
"stock": 0,
"disabled": true
},
{
"value": "165cm",
"stock": 19,
"disabled": false
}
]
},
{
"value": "红绿色调00364",
"disabled": false,
"heights": [
{
"value": "160cm",
"stock": 50,
"disabled": false
},
{
"value": "165cm",
"stock": 100,
"disabled": false
}
]
}
]
最终我们需要这样的数据来显示 就好了
我认为这样的数据 才是 最符合 的 很明显 后端给的数据 差距太大 说实话
我一下子没有想起来怎么把上面的数据处理成下面这样
我也是搜了搜
使用 new Map 映射一下 最后在Array.from(new Map.values) 映射出来就好了
我直接上代码吧
colorOptions: [],
heightOptions: [],
filterOptions: [], 中转 相当于选择了规格1 的经过 去筛选规格2 的显示
selectedColor: null, //规格1选择的结果
selectedHeight: null //规格1选择的结果
initOptions() {
const colorMap = new Map();
const heightMap = new Map();
// 首先收集所有颜色和身高选项
this.originalData.forEach(product => {
// 处理颜色选项
if (!colorMap.has(product.masterAttrValue)) {
colorMap.set(product.masterAttrValue, {
value: product.masterAttrValue,
disabled: false, // 初始不禁用
heights: new Map() // 存储身高和对应的库存
});
}
const colorOption = colorMap.get(product.masterAttrValue);
colorOption.heights.set(product.slaveAttrValue, product.stock);
// 处理身高选项
if (!heightMap.has(product.slaveAttrValue)) {
heightMap.set(product.slaveAttrValue, {
value: product.slaveAttrValue,
disabled: product.stock === 0, // 身高选项的禁用状态基于库存
colors: new Map() // 存储颜色和对应的库存
});
}
const heightOption = heightMap.get(product.slaveAttrValue);
heightOption.colors.set(product.masterAttrValue, product.stock);
});
// 转换颜色选项:只有当所有身高都缺货时才禁用颜色
this.colorOptions = Array.from(colorMap.values()).map(color => {
const hasStock = Array.from(color.heights.values()).some(stock => stock > 0);
return {
...color,
disabled: !hasStock,
heights: Array.from(color.heights.entries()).map(([height, stock]) => ({
value: height,
stock,
disabled: stock === 0
}))
};
});
// 转换身高选项
this.heightOptions = Array.from(heightMap.values()).map(height => ({
...height,
colors: Array.from(height.colors.entries()).map(([color, stock]) => ({
value: color,
stock,
disabled: stock === 0
}))
}));
console.log(this.colorOptions, 'this.colorOptions');
console.log(this.heightOptions, 'this.colorOptions');
},
上面的数据到下面 这个方法就够了
然后页面上显示我也拿出来
<div class="cate-selected-box">
<div class="cate-title"> {{ info.masterAttrName }}</div>
<ul class="cate-list">
<li class="level1-item" v-for="color in colorOptions" :key="color.value" @click="selectColor(color)"
:class="{ 'disabled': color.disabled, 'selected': selectedColor === color.value }">
{{ color.value }}
<span v-if="color.disabled">(缺货)</span>
</li>
</ul>
<div class="cate-title"> {{ info.slaveAttrName }}</div>
<ul class="cate-list" v-if="filterOptions.length">
<li class="level1-item" v-for="item in filterOptions" v-if="item.value != '-'" :key="item.value"
@click.stop="selectHeight(item)"
:class="{ 'disabled': item.disabled, 'selected': selectedHeight === item.value }">
{{ item.value }}
<span v-if="item.disabled">(缺货)</span>
</li>
</ul>
<div class="selected-info" v-if="info.productSpecials && info.productSpecials.length > 1">
<div class="item">
<div class="label">
已选择:
</div>
<!-- && -->
<div class="value"
v-if="(info.slaveAttrValues && info.slaveAttrValues.length) && (info.masterAttrValues && info.masterAttrValues.length)">
<div v-if="selectedColor && selectedHeight">
{{ selectedColor }} - {{ selectedHeight }}
</div>
</div>
<div class="value"
v-if="(!info.slaveAttrValues) && (info.masterAttrValues && info.masterAttrValues.length)">
<div v-if="selectedColor">
{{ selectedColor }}
</div>
</div>
</div>
</div>
</div>
li {
list-style: none;
padding: 0;
margin: 0;
}
ul {
padding: 0;
margin: 0;
}
.cate-selected-box {
.cate-title {
font-weight: 700;
margin: 10px 0;
}
.selected-info {
margin: 15px;
margin-top: 25px;
.item {
display: flex;
align-items: center;
.label {
color: 858a99;
}
.value {
color: #6034b9;
margin-left: 10px;
}
}
}
.cate-list {
cursor: pointer;
display: flex;
flex-wrap: wrap;
align-items: center;
.level1-item {
padding: 10px 20px;
border: 1px solid #f7f8f9;
border-radius: 5px;
transition: all 0.3s;
margin: 6px;
}
.level1-item:hover {
border: 1px solid #6034b9;
}
.level1-item:nth-child(n+2) {
// margin-left: 10px;
// margin: 10px;
}
}
}
.disabled {
color: #ccc;
cursor: not-allowed;
}
.selected {
background-color: #6034b9;
color: white;
border-color: #6034b9;
}
这一部分的样式我也显示出来了
大家如果把这个放到vue 文件中 是直接能够显示效果的
这里面的难点其实是这个 new Map 的使用 我也使用的好少 Es6 的方法如果说不使用 这个 其实 也能够想办法 把这个处理好 但是方法不太好想
这些都是经验吗 每次记一点 下次遇到了就能有想法了
学习前端就是这样 哪怕你死记硬背 有时候 也有用 就会知道什么方法处理什么问题