前端SKU商品多规格选择问题优化

文章描述了在实现前端商品多规格选择功能时,遇到的一个bug,即当数据源属性超过2个时会出现问题。作者提到参考的文章没有详细解释该问题,但重点在于`associateAttributes`函数的实现和bug表现。
摘要由CSDN通过智能技术生成

最近公司有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>

前端商品多规格选择问题 SKU 算法实现优化2.0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大笨熊不熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值