解决sku属性选择问题原来可以如此简单,你也值得拥有

1,104 阅读3分钟

写在前面

  在沉淀的过程中,无意中看到自己以前写过的一篇文章 浅谈微信小程序之sku属性选择思路。感觉代码写得很臃肿,而且逻辑比较混乱,于是决心重新捣鼓一遍,也算是对自己过去的一个致敬。如果大家有更好的意见及改进方案,欢迎在评论区指出,不胜感激!

需求

  因为在此前的博文中有写过类似的需求,因此在此粗略地点一下就好:

  • 选择颜色时,尺码要根据后端返回数据自动进行筛选; image.png
  • 再次点击相同颜色,取消选择时,需要取消尺码的筛选; image.png
  • 选择尺码时,颜色要根据后端返回数据自动进行筛选; image.png
  • 再次点击相同尺码,取消选择时,需要取消颜色的筛选; image.png
  • 选中尺码再选中颜色属性时,需要对尺码进行筛选,选中颜色再选中尺码属性时,需要对颜色进行筛选; image.png

image.png

  • 未选择产品属性时,提示请选择产品属性; image.png
  • 已选择产品属性时,显示选中的产品属性;

重点思路分析

  • 首先要明白,vue框架是数据驱动视图,由数据的变化改变视图的变化。所以按钮的禁用条件是计算属性,是通过选中的属性来进行筛选,而不应该在点击方法中把禁用的条件写进去。

  • 其次,如何判断是否是选中/取消选中当前产品属性是一个需要解决的问题,可以使用两种思路解决:

    1. 选中则将选择的属性赋值给selectSize或者selectColor,取消选择时,通过判断当前选中属性和selectSize或者SelectColor是否相同。如果相同,将对应属性置为''return掉即可;如果不同,则将当前的值赋值给selectSize或者SelectColor即可。
    2. 为当前产品的所有尺码和颜色集合分别增加一个默认为falseselect字段。选中产品属性时,将对应产品属性的select字段取反即可(但由于还是要获取并显示当前选中的属性,所以最后还是要像第一种方法一样进行判断,因此这种方法只用于不显示选中的产品属性的情形上,在需要提示选中产品属性的需求下,这种方法显得明显多余)。
  • 判断选中当前产品属性A,另一个产品属性B的禁用状态(禁用的计算属性): 首先要明白B的禁用是和A的选中状态挂钩的。如果A选中属性没有值,则不需要禁用。如果A选中属性有值,则需要在后端返回数据中找到符合A属性的数组C,然后再用find进行判断,如果C中找不到A,则需要禁用,此时返回undefind,而最后的结果是要返回true;如果C中找到得到A,则不需要禁用,返回false,因此都需要取反来判断。

源码放送

//test.vue
<template>
  <div class="app-container">
    <div class="mt10 flex-middle">
      <span class="mr10">颜色:</span>
      <el-button
        size="small"
        v-for="item in colorList"
        :Key="item"
        :disabled="colorDisabled(item)"
        :class="[selectColor == item && 'active']"
        @click="handleColorClick(item)"
        >{{ item }}</el-button
      >
    </div>
    <div class="mt20 flex-middle">
      <span class="mr10">尺码:</span>
      <el-button
        size="small"
        v-for="item in sizeList"
        :Key="item"
        :disabled="sizeDisabled(item)"
        :class="[selectSize == item && 'active']"
        @click="handleSizeClick(item)"
        >{{ item }}</el-button
      >
    </div>
    <div class="mt20 flex-middle">
      <div v-if="hasSelected">{{ getSelectAttribute }}</div>
      <div v-else>请选择产品属性</div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selectSize: '',
      selectColor: '',
      productList: [
        { id: 3795, price: '9.99', color: '白色', gender: '通用', size: '通用-均码' },
        { id: 3796, price: '66.66', color: '富贵色', gender: '男士', size: '男士-38' },
        { id: 3797, price: '34.56', color: '黄色', gender: '通用', size: '通用-41' },
        { id: 3798, price: '34.56', color: '黄色', gender: '通用', size: '通用-42' },
        { id: 3799, price: '34.56', color: '绿色', gender: '通用', size: '通用-41' },
        { id: 3800, price: '34.56', color: '绿色', gender: '通用', size: '通用-42' },
        { id: 3801, price: '12.34', color: '测试色', gender: '通用', size: '通用-测试均码' },
        { id: 3802, price: '100.00', color: '黑色', gender: '男士', size: '男士-37' },
        { id: 3803, price: '31.23', color: 'dsad', gender: '男士', size: '男士-323' },
        { id: 3804, price: '99.99', color: '测试', gender: '通用', size: '通用-41' },
        { id: 3805, price: '99.99', color: '测试', gender: '通用', size: '通用-42' },
        { id: 3806, price: '99.99', color: '测试', gender: '通用', size: '通用-43' }
      ]
    }
  },
  computed: {
    hasSelected() {
      return this.selectSize.length || this.selectColor.length
    },

    getSelectAttribute() {
      return `已选属性:${this.selectColor} ${this.selectSize} `
    },

    colorList() {
      return [...new Set(this.productList.map((item) => item.color))]
    },

    sizeList() {
      return [...new Set(this.productList.map((item) => item.size))]
    },

    sizeDisabled({ productList, selectColor }) {
      return (size) => {
        if (!selectColor) return false
        const sameColorList = productList.filter(({ color }) => color == selectColor)
        return !sameColorList?.find((item) => item.size == size)
      }
    },

    colorDisabled({ productList, selectSize }) {
      return (color) => {
        if (!selectSize) return false
        const sameSizeList = productList.filter(({ size }) => size == selectSize)
        return !sameSizeList?.find((item) => item.color == color)
      }
    }
  },

  methods: {
    handleColorClick(color) {
      if (this.selectColor == color) return this.selectColor = ''
      this.selectColor = color
    },

    handleSizeClick(size) {
      if (this.selectSize == size) return this.selectSize = ''
      this.selectSize = size
    }
  }
}
</script>

<style lang="scss" scoped>
.active {
  border: 1px solid #000;
}
.el-button.el-button:hover,
.el-button.el-button:focus {
  color: #606266;
  background: #fff;
}
</style>

写在最后

  其实这份代码在处理颜色和尺码的过程中,有一些重复的逻辑代码,有兴趣的小伙伴可以抽取公共方法,然后再调用即可。


                            学习&总结