最近公司有sku库存的需求,于是网上查找了一些文章,看了很多找到一篇合适的文章,于是参考一下,运行发现每个数据源是两个的时候不会有问题,但是凡是其中有一个数据源超过2个就会有bug出现: 参考的原文链接在末尾
————————————————————————————————————————————————————————
————————————————————————————————————————————————————————
文章末尾链接里解释的很到位,这里只说发现的bug - associateAttributes函数
<template>
<div class="root">
<div v-for="(property, propertyIndex) in properties" :key="propertyIndex">
<p>{{ property.name }}</p>
<div class="sku-box-area">
<template v-for="(attribute, attributeIndex) in property.attributes" :key="attributeIndex">
<div
:class="[
'sku-box',
'sku-text',
attribute.isActive ? 'active' : '',
attribute.isDisabled ? 'disabled' : ''
]"
@click="handleClickAttribute(propertyIndex, attributeIndex)"
>
{{ attribute.value }}
</div>
</template>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'SkuSelector2',
components: {},
data() {
return {
properties: [
{
id: '1',
name: '容量',
attributes: [
{ value: '1L', isActive: false, isDisabled: false },
{ value: '4L', isActive: false, isDisabled: false },
{ value: '6L', isActive: false, isDisabled: false }
]
},
{
id: '2',
name: '颜色',
attributes: [
{ value: '红色', isActive: false, isDisabled: false },
{ value: '黑色', isActive: false, isDisabled: false }
]
},
{
id: '3',
name: '优惠套餐',
attributes: [
{ value: '套餐一', isActive: false, isDisabled: false },
{ value: '套餐二', isActive: false, isDisabled: false }
]
}
],
skuList: [
{ id: '10', attributes: ['1L', '红色', '套餐一'] },
{ id: '20', attributes: ['1L', '黑色', '套餐二'] },
{ id: '30', attributes: ['4L', '红色', '套餐一'] },
{ id: '40', attributes: ['4L', '红色', '套餐二'] }
],
matrix: [], // 邻接矩阵存储无向图
vertexList: [], // 顶点数组
selected: [] // 当前已选的 attribute 列表
}
},
computed: {},
mounted() {
this.initEmptyAdjMatrix()
this.setAdjMatrixValue()
},
methods: {
// 当点击某个 attribute 时,如:黑色
handleClickAttribute(propertyIndex, attributeIndex) {
const attr = this.properties[propertyIndex].attributes[attributeIndex]
// 若选项置灰,直接返回,表现为点击无响应
if (attr.isDisabled) {
return
}
// 重置每个 attribute 的 isActive 状态
const isActive = !attr.isActive
this.properties[propertyIndex].attributes[attributeIndex].isActive = isActive
if (isActive) {
this.properties[propertyIndex].attributes.forEach((attr, index) => {
if (index !== attributeIndex) {
attr.isActive = false
}
})
}
// 维护当前已选的 attribute 列表
this.selected = []
this.properties.forEach((prop) => {
prop.attributes.forEach((attr) => {
if (attr.isActive) {
this.selected.push(attr.value)
}
})
})
// 重置每个 attribute 的 isDisabled 状态
this.properties.forEach((prop) => {
prop.attributes.forEach((attr) => {
attr.isDisabled = !this.canAttributeSelect(attr)
})
})
},
// 构造初始空邻接矩阵存储无向图
initEmptyAdjMatrix() {
this.properties.forEach((prop) => {
prop.attributes.forEach((attr) => {
this.vertexList.push(attr.value)
})
})
for (let i = 0; i < this.vertexList.length; i++) {
this.matrix[i] = new Array(this.vertexList.length).fill(0)
}
},
// 根据 skuList 和 properties 设置邻接矩阵的值
setAdjMatrixValue() {
this.skuList.forEach((sku) => {
this.associateAttributes(sku.attributes, sku.id)
})
this.properties.forEach((prop) => {
this.associateAttributes(prop.attributes, '1')
})
},
// 将 attributes 属性组中的属性在无向图中联系起来
associateAttributes(attributes, skuId) {
attributes.forEach((attr1) => {
console.log('=======', attr1)
attributes.forEach((attr2) => {
console.log('---------------', attr2)
if (attr1 != attr2 || attr1.value != attr2.value) {
attr1 = attr1.value ? attr1.value : attr1
attr2 = attr2.value ? attr2.value : attr2
console.log('+++++++', attr1, attr2)
const index1 = this.vertexList.indexOf(attr1)
const index2 = this.vertexList.indexOf(attr2)
console.log('+++///--------', attr1, attr2, index1, index2)
if (index1 > -1 && index2 > -1) {
if (this.matrix[index1][index2]) {
this.matrix[index1][index2].add(skuId)
} else {
this.matrix[index1][index2] = new Set([skuId])
}
}
}
// 因 properties 与 skuList 数据结构不一致,需作处理
// if (attr1 !== attr2 || attr1.value !== attr2.value) {
// if (attr1.value && attr2.value) {
// console.log('渲染列表', attr1, attr2)
// attr1 = attr1.value
// attr2 = attr2.value
// }
// console.log('循环列表===', attr1, attr2)
// const index1 = this.vertexList.indexOf(attr1)
// const index2 = this.vertexList.indexOf(attr2)
// console.log(attr1, attr2, index1, index2)
// if (index1 > -1 && index2 > -1) {
// if (this.matrix[index1][index2]) {
// this.matrix[index1][index2].add(skuId)
// } else {
// this.matrix[index1][index2] = new Set([skuId])
// }
// }
// }
})
})
console.log(this.matrix)
},
// 判断当前 attribute 是否可选,返回 true 表示可选,返回 false 表示不可选,选项置灰
canAttributeSelect(attribute) {
if (!this.selected || !this.selected.length || attribute.isActive) {
return true
}
let res = []
this.selected.forEach((value) => {
const index1 = this.vertexList.indexOf(value)
const index2 = this.vertexList.indexOf(attribute.value)
res.push(this.matrix[index1][index2])
})
console.log(attribute.value, '->', res)
if (res.some((item) => item === 0)) {
return false
} else if (res.some((item) => item.has('1'))) {
return true
} else {
const first = res[0]
const others = res.slice(1)
return Array.from(first).some((skuId) => others.every((item) => item.has(skuId)))
}
}
}
}
</script>
<style>
.root {
width: 350px;
padding: 24px;
}
.sku-box-area {
display: flex;
flex: 1;
flex-direction: row;
flex-wrap: wrap;
}
.sku-box {
border: 1px solid #cccccc;
border-radius: 6px;
margin-right: 12px;
padding: 8px 10px;
margin-bottom: 10px;
}
.sku-text {
font-size: 16px;
line-height: 16px;
color: #666666;
}
.active {
border-color: #ff6600;
color: #ff6600;
}
.disabled {
opacity: 0.5;
border-color: #e0e0e0;
color: #999999;
}
</style>