封装sku组件

1. 准备模板渲染规格数据

使用Vite快速创建一个Vue项目,在项目中添加请求插件axios,然后新增一个SKU组件,在根组件中把它渲染出来,下面是规格内容的基础模板

封装sku组件_第1张图片






2. 选中和取消选中实现

基本思路:

  1. 每一个规格按钮都拥有自己的选中状态数据-selected,true为选中,false为取消选中
  2. 配合动态class,把选中状态selected作为判断条件,true让active类名显示,false让active类名不显示
  3. 点击的是未选中,把同一个规格的其他取消选中,当前点击项选中;点击的是已选中,直接取消



3. 规格禁用功能实现

封装sku组件_第2张图片

3.1 生成路径字典

幂等算法 power-set.js


export default function bwPowerSet (originalSet) {
    const subSets = []

    // We will have 2^n possible combinations (where n is a length of original set).
    // It is because for every element of original set we will decide whether to include
    // it or not (2 options for each set element).
    const numberOfCombinations = 2 ** originalSet.length

    // Each number in binary representation in a range from 0 to 2^n does exactly what we need:
    // it shows by its bits (0 or 1) whether to include related element from the set or not.
    // For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
    // include only "2" to the current set.
    for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
        const subSet = []

        for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
            // Decide whether we need to include current element into the subset or not.
            if (combinationIndex & (1 << setElementIndex)) {
                subSet.push(originalSet[setElementIndex])
            }
        }

        // Add current subset to the list of all subsets.
        subSets.push(subSet)
    }

    return subSets
}

获取有效路径字典:






console.log(effectiveSkus)

封装sku组件_第3张图片

console.log(pathMap)

封装sku组件_第4张图片

3.2 根据路径字典设置初始化状态

思路:判断规格的name属性是否能在有效路径字典中找到,如果找不到就禁用

// 1. 定义初始化禁用状态
// specs:商品源数据 pathMap:路径字典
const initDisabledState = (specs, pathMap) => {
  // 约定:每一个按钮的状态由自身的disabled进行控制
  specs.forEach(item => {
    item.values.forEach(val => {
      // 路径字典中查找是否有数据 有-可以点击 没有-禁用
      val.disabled = !pathMap[val.name]
    })
  })
}

// 2. 在数据返回后进行初始化处理
let patchMap = {}
const getGoods = async () => {
  // 1135076  初始化就有无库存的规格
  // 1369155859933827074 更新之后有无库存项(蓝色-20cm-中国)
  const res = await axios.get('http://pcapi-xiaotuxian-front-devtest.itheima.net/goods?id=1135076')
  goods.value = res.data.result
  pathMap = getPathMap(goods.value)
  // 初始化更新按钮状态
  initDisabledState(goods.value.specs, pathMap)
}

// 3. 适配模板显示

{{val.name }}

3.3 根据路径字典设置组合禁用状态

思路:

  1. 根据当前选中规格,生成顺序规格数组 => [‘黑色’, undefined, undefined ]
  2. 遍历每一个规格按钮

如何规格按钮已经选中,忽略判断
如果规格按钮未选中,拿着按钮的name值按顺序套入匹配数组对应的位置,最后过滤掉没有值的选项,通过-进行拼接成字符串key, 去路径字典中查找,没有找到则把当前规格按钮禁用

// 获取选中匹配数组 ['黑色',undefined,undefined]
const getSelectedValues = (specs) => {
  const arr = []
  specs.forEach(spec => {
    const selectedVal = spec.values.find(value => value.selected)
    arr.push(selectedVal ? selectedVal.name : undefined)
  })
  return arr
}

const updateDisabledState = (specs, pathMap) => {
  // 约定:每一个按钮的状态由自身的disabled进行控制
  specs.forEach((item, i) => {
    const selectedValues = getSelectedValues(specs)
    item.values.forEach(val => {
      if (val.selected) return
      const _seletedValues = [...selectedValues]
      _seletedValues[i] = val.name
      const key = _seletedValues.filter(value => value).join('*')
      // 路径字典中查找是否有数据 有-可以点击 没有-禁用
      val.disabled = !pathMap[key]
    })
  })  
}

4. 产出 prop 数据

const changeSku = (item, val) => {
  // 省略...
  // 产出SKU对象数据
  const index = getSelectedValues(goods.value.specs).findIndex(item => item === undefined)
  if (index > -1) {
    console.log('找到了,信息不完整')
  } else {
    console.log('没有找到,信息完整,可以产出')
    // 获取sku对象
    const key = getSelectedValues(goods.value.specs).join('*')
    const skuIds = pathMap[key]
    console.log(skuIds)
    // 以skuId作为匹配项去goods.value.skus数组中找
    const skuObj = goods.value.skus.find(item => item.id === skuIds[0])
    console.log('sku对象为', skuObj)
  }
}

你可能感兴趣的:(javascript,vue.js,前端)