其他分享
首页 > 其他分享> > vue3项目-小兔鲜儿笔记-商品详情页02

vue3项目-小兔鲜儿笔记-商品详情页02

作者:互联网

1. SKU和SPU概念

SPU代表一个商品,这个商品可以拥有很多属性

SKU代表这个商品可选规格的任意组合,是库存单位唯一标识

 

2. 路径字典

大致步骤

  1. 根据后台返回的sku数据得到有效sku组合(inventory > 0)

  2. 处理sku数组,使用power-set算法得到sku数组的子集

    • 比如:['蓝色', '中国'] => ['蓝色'], ['中国'], ['蓝色', '中国']

  3. 将子集内容作为key,对应查找到的skuId作为value存入路径对象中

    • 比如:['蓝色','中国'] => '蓝色☆中国': 1238978971

import bwPowerSet from '@/vender/power-set'

const spliter = '★'
const pathMap = {}

export const usePathMap = (skus) => {
  skus.forEach((sku) => {
    if (sku.inventory > 0) {
      // 3.处理skus数组,参考例子:['蓝色','中国'] => ['蓝色'], ['中国'], ['蓝色','中国']
      // 3.1 要先处理skus数组为上面例子的形式,将属性名映射成数组
      const valueArr = sku.specs.map((value) => value.valueName)
      // 3.2 使用power-set算法得到skus数组的子集
      const valuePowerSet = bwPowerSet(valueArr)
      // 4.1 处理子集的形式,把数组映射成字符串得到key值
      valuePowerSet.forEach((arr) => {
        const key = arr.join(spliter)
        // 4.2 把key和skuId作为key-value存储到路径字典
        // 4.2.1 如果pathMap[key]已存在,则继续Push skuID
        // 4.2.2 如果pathMap[key]不存在,则设置成数组
        if (key !== '') {
          if (pathMap[key]) {
            pathMap[key].push(sku.id)
          } else {
            pathMap[key] = [sku.id]
          }
        }
      })
    }
  })

  return pathMap
}

 

3. 规格组件的选中效果

大致步骤

  1. // 关键数据:goods.specs = [spec, spec, spec]

    // spec = {name: '颜色', values: [{valueName: '黑色'}, {valueName: '蓝色'}]}

    // 选中和禁用的状态:selected和disabled,这两个状态都是加到每个按钮上的

  2. 绑定按钮点击事件,完成选中和取消选中

    • 当前点的是选中,取反

    • 当前点的是未选中,先遍历当前规格的所有按钮,全部取消选中,再当前按钮选中。

const changeSku = (goods, specs, spec, value) => {
  if (value.disabled) return
  if (value.selected) {
    value.selected = false
  } else {
    spec.values.forEach((val) => {
      if (val.name !== value.name) {
        val.selected = false
      }
    })
    value.selected = true
    。。。
}

 

4. 规格组件-按钮禁用状态

目的:在组件初始化的时候,以及点击规格中按钮的时候,去更新其他按钮的禁用状态

  1. 获取当前选中的值的数组:['黑色', undefined, undefined]

  2. 遍历按钮:先遍历每一种规格,取出当前选中的值的数组:['黑色', undefined, undefined],再遍历每一个按钮

    • 如果这个按钮已经选中,忽略判断禁用状态

    • 如果这个按钮没被选中,则拿着这个按钮的值按顺序去套入,得到套入后的数组,过滤掉undefined,加入☆拼接成key,比如:蓝色☆中国,拿这个key去路径字典中查找,没有查找到就设置这个按钮为禁用状态

// 获取规格参数数组,参考数据:如果点击了蓝色,其他未点 => ['蓝色', undefined, undefined]
export const getSelectedArr = (specs) => {
  const selectedArr = []
  specs.forEach((spec) => {
    const selectedVal = spec.values.find((val) => val.selected)
    selectedArr.push(selectedVal ? selectedVal.name : undefined)
  })

  return selectedArr
}
// 更新按钮的禁用状态
export const updateDisable = (specs, pathMap) => {
  // 先遍历每一种规格,取出当前选中的值的数组
  specs.forEach((spec, i) => {
    const selectedArr = getSelectedArr(specs)
    // 再遍历规格中的每一个按钮,拿按钮的值按顺序套入
    spec.values.forEach((val) => {
      if (val.name !== selectedArr[i]) {
        selectedArr[i] = val.name
        // 去除undefined得到key值,到路径字典查找是否有该key,无则设置该按钮disabled为true
        const key = selectedArr.filter((item) => item).join(spliter)
        val.disabled = pathMap[key] ? false : true
      }
    })
  })
}
const changeSku = (goods, specs, spec, value) => {
  if (value.disabled) return
  if (value.selected) {
    value.selected = false
  } else {
    spec.values.forEach((val) => {
      if (val.name !== value.name) {
        val.selected = false
      }
    })
    value.selected = true
    // 点击按钮时更新按钮的禁用状态
    updateDisable(specs, pathMap)
    // 当选择了完整的sku之后,触发change事件让父组件收到更新的sku
    const validSelectedArr = getSelectedArr(specs).filter((v) => v)
    if (validSelectedArr.length === specs.length) {
      // 完整的sku
      const key = validSelectedArr.join('★')
      const skuIds = pathMap[key]
      const sku = goods.skus.find((sku) => sku.id === skuIds[0])
      emit('change', {
        skuId: sku.id,
        price: sku.price,
        oldPrice: sku.oldPrice,
        inventory: sku.inventory,
        specsText: sku.specs
          .reduce((p, c) => `${p} ${c.name}:${c.valueName}`, '')
          .trim()
      })
    } else {
      emit('change', {})
    }
  }
}
父组件:
// 监听sku组件的自定义事件,拿到更新的sku
const changeSku = (sku) => {
  console.log(sku)
  // 用更新的sku去修改goods的现价和原价还有库存
  goods.value.price = sku.price
  goods.value.oldPrice = sku.oldPrice
  goods.value.inventory = sku.inventory
}
// 组件初始化的时候根据传来的skuid默认选中按钮
export const initSelected = (goods, skuId) => {
  const sku = goods.skus.find((sku) => sku.id === skuId)
  // 根据sku中的spec描述信息,遍历specs数组,找到对应的按钮并选中
  if (sku) {
    goods.specs.forEach((spec, i) => {
      // 找到sku描述的规格名
      if (spec.name === sku.specs[i].name) {
        spec.values.forEach((value) => {
          // 找到sku描述的属性名
          if (value.name === sku.specs[i].valueName) {
            value.selected = true
          }
        })
      }
    })
  }
}

 

标签:02,sku,const,鲜儿,value,详情页,key,按钮,specs
来源: https://www.cnblogs.com/jzhFlash/p/16660129.html