首页 > 其他 > 详细

类似淘宝sku选择

时间:2020-02-29 18:27:32      阅读:70      评论:0      收藏:0      [点我收藏+]
<template>
  <div class="wrap-sku">
    <div class="product-box">
      <div class="product-content">
        <div class="product-delcom" v-for="(productItem,indexs) in list" :key="indexs">
          <p>{{ productItem.name }}</p>
          <ul class="product-footerlist">
            <!--
                currentChoose[ProductItem.name] === oItem.name // 选中项对象中Key是否存在规格属性 存在就选上red
                否则oItem.hasStock代表是否可以被选择,不能被选择就直接置灰色
            -->
            <li v-for="(oItem,index) in productItem.items"
                :key="index"
                @click="clickSku(productItem.name, oItem)"
                :class="[currentChoose[productItem.name] === oItem.name ? ‘activeStock‘ : oItem.hasStock ? ‘isStock‘ : ‘noStock‘]">
              {{ oItem.name }}
            </li>
          </ul>
        </div>
      </div>
      <div style="font-size: 20px;margin-top: 100px">选中的属性: 性别:{{ currentChoose.sex }}, 颜色:{{ currentChoose.color }}, 大小:{{ currentChoose.size }}</div>
    </div>
  </div>
</template>

<script>
  // 需要被找到的规格值数组 (创造子集数组是非常重要的一步事情)
  const getKey = (currentChoose, groupName, item) => {
    const obj = { ...currentChoose }
    // 这一步也是非常重要的
    // 很多人不懂的事,我点击男 groupName是sex 然后 item.name值是男
    // obj[groupName]是对象里面的sex值等于 刚刚传进来的 (item.name值是男)
    // 那么obj打出来为啥还有sex值为女的呢。这里按道理都是男啊,为啥呢
    // 理由如下: 当我点击规格事件的 currentChoose[对应的key值已经被我存起来了](具体请看点击事件)
    obj[groupName] = item.name
    // 建造子集数组(重要一步)它将是拿去去交集的一个点
    const arr = []
    // 找到存再的规格值,进行push新的子集中
    for (const i in obj) if (obj[i] !== ‘‘) arr.push(obj[i])
    return arr
  }
  // 一个数组是否为sku数组的子集(parent 单个sku的数组)
  const isChildrenArr = (parent, child) => {
    // every()方法是js中的迭代方法,用于检测数组中的元素是否满足指定条件。
    //     1、依次执行数组元素,如果一个元素不满足条件就返回false,不会继续执行后面的元素判断;所有数组元素都满足条件则返回true。
    //     2、不会改变原数组。
    // includes() 方法用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false。
    /** ********** 思路:非常重要也是最关键的一步*********/
    // 1. 找得到的情况:
    // 如: 当我开始没选中 child(建造子集数组的值)为 [男]
    // 然后遍历V等于男,当我 parent为[‘男‘, ‘白色‘, ‘100‘],那么我的男在我里面存在,就返回为true
    // 2. 找不到的情况:
    // 如:  当我开始选中白色,那么我child(建造子集数组的值)是[男,白色]
    // 然后遍历V等于男,当我 parent为[‘男‘, ‘蓝色‘, ‘100‘]
    // 首先我第一次遍历男 确实在我数组里面存在,然后再找到白色进去遍历,那么此时白色在我parent数组里面不存在。
    // 那么就直接返回为false, 因为上面有说到 every()方法 如果一个元素不满足条件就返回false,不会继续执行后面的元素判断
    return child.every(v => {
      return parent.includes(v)
    })
  }
  // 获取规格值属性数组
  const getCheckedStockList = (list, stockList, currentChoose) => list.map((group) => {
    // 遍历规格值
    const items = group.items.map((item) => {
      // some()方法用于检测数组中的元素是否满足指定条件(函数提供)。
      // some()方法会依次执行数组的每个元素:
      // 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
      // 如果没有满足条件的元素,则返回false。
      // 注意some() 不会对空数组进行检测, 注意some() 不会改变原始数组。
      // 检测数组中的元素是否满足指定条件
      const hasStock = stockList.some(stock => {
        // 找出sku数组中符合条件的元素(子集节点找得到并且库存数量大于0)如果你的条件不是库存大于0 而是其它,请你自己改掉 后面的条件
        return isChildrenArr(stock.key, getKey(currentChoose, group.name, item)) && stock.stock > 0
      })
      return { ...item, hasStock }
    })
    return { ...group, items }
  })

  // 无限级SKU选择(把方法拷贝,不是vue项目也能用哦,思想一样)
  export default {
    data () {
      return {
        // sku列表
        stockList: [
          { key: [, 白色, 100], stock: 2 },
          { key: [, 白色, 200], stock: 0 },
          { key: [, 红色, 100], stock: 2 },
          { key: [, 红色, 300], stock: 1 },
          { key: [, 红色, 200], stock: 2 },
          { key: [, 蓝色, 200], stock: 2 },
          { key: [, 白色, 200], stock: 2 },
          { key: [, 白色, 100], stock: 2 }
        ],
        // 规格值数组(无限级SKU选择)
        list: [
          {
            name: sex,
            items: [
              { name:  },
              { name:  }
            ]
          },
          {
            name: color,
            items: [
              { name: 白色 },
              { name: 红色 },
              { name: 蓝色 }
            ]
          },
          {
            name: size,
            items: [
              { name: 100 },
              { name: 200 },
              { name: 300 }
            ]
          }
        ],
        // 选中对象
        currentChoose: {
          color: ‘‘,
          size: ‘‘,
          sex: ‘‘
        }
      }
    },
    created () {
      // 初始化规格 sku列表查询对应的路径
      this.list = getCheckedStockList(this.list, this.stockList, this.currentChoose)
    },
    methods: {
      // 规格属性点击事件
      clickSku (groupName, item) {
        // 如果我当前的规格属性不能被选选中,那么直接返回
        if (!item.hasStock) return
        // 取出对应的数据
        const { currentChoose, stockList, list } = { stockList: this.stockList, list: this.list, currentChoose: this.currentChoose }
        // 如果我当前选中的规格值存在,在我当前选中项数组里面,那么就把选中项去掉,否则就把当前选中规格的key值赋值为当前选中的value值
        const nextChoose = currentChoose[groupName] === item.name
          ? { ...currentChoose, [groupName]: ‘‘ }
          : { ...currentChoose, [groupName]: item.name }
        // 每次点击都需要去sku列表重新查询对应的路径
        const checkedStockList = getCheckedStockList(list, stockList, nextChoose)
        // 赋值选中对象
        this.currentChoose = nextChoose
        // 赋值规格
        this.list = checkedStockList
      }
    }
  }
</script>

<style lang="less">
  .wrap-sku {
    .activeStock {background-color: red;}
    .isStock {background-color: #fff;}
    .noStock {background-color: #eee;cursor: default !important;}
    .product-box {
      width: 1200px;
      display: block;
      margin: 0 auto;
    }
    .product-delcom {
      color: #323232;
      font-size: 26px;
      padding: 30px 0;
    }
    .product-footerlist li {
      border: 1px solid #606060;
      border-radius: 5px;
      color: #606060;
      text-align: center;
      padding: 10px 30px;
      list-style: none;
      float: left;
      margin-right: 20px;
      cursor: pointer;
    }
  }
</style>

 

效果图: 

技术分享图片

 

类似淘宝sku选择

原文:https://www.cnblogs.com/plBlog/p/12384361.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!