vue3前端开发-小兔鲜项目-sku的实现

打印 上一主题 下一主题

主题 554|帖子 554|积分 1662

vue3前端开发-小兔鲜项目-sku的实现!这是一个会计学的特殊专业名词,可以理解为产品的型号,规格的货品计量单元。
它是一组数据的混合体。比如:尺寸,质料,品质,等等。组合在一起形成的一个混合数组对象。

下面是小兔鲜项目标官方提供的一个下载地址:
里面有我们需要的一些插件代码。包括本次项目测试内容用到的sku插件代码。

地址:百度网盘 请输入提取码
您可以去这个地址里下载百度网盘内的代码内容。里面有本次分享的插件sku内容了!

 
它的位置,照旧在项目标根components下面的。

  1. <script>
  2. import { watchEffect } from 'vue'
  3. import getPowerSet from './power-set'
  4. const spliter = '★'
  5. // 根据skus数据得到路径字典对象
  6. const getPathMap = (skus) => {
  7.   const pathMap = {}
  8.   if (skus && skus.length > 0) {
  9.     skus.forEach(sku => {
  10.       // 1. 过滤出有库存有效的sku
  11.       if (sku.inventory) {
  12.         // 2. 得到sku属性值数组
  13.         const specs = sku.specs.map(spec => spec.valueName)
  14.         // 3. 得到sku属性值数组的子集
  15.         const powerSet = getPowerSet(specs)
  16.         // 4. 设置给路径字典对象
  17.         powerSet.forEach(set => {
  18.           const key = set.join(spliter)
  19.           // 如果没有就先初始化一个空数组
  20.           if (!pathMap[key]) {
  21.             pathMap[key] = []
  22.           }
  23.           pathMap[key].push(sku.id)
  24.         })
  25.       }
  26.     })
  27.   }
  28.   return pathMap
  29. }
  30. // 初始化禁用状态
  31. function initDisabledStatus (specs, pathMap) {
  32.   if (specs && specs.length > 0) {
  33.     specs.forEach(spec => {
  34.       spec.values.forEach(val => {
  35.         // 设置禁用状态
  36.         val.disabled = !pathMap[val.name]
  37.       })
  38.     })
  39.   }
  40. }
  41. // 得到当前选中规格集合
  42. const getSelectedArr = (specs) => {
  43.   const selectedArr = []
  44.   specs.forEach((spec, index) => {
  45.     const selectedVal = spec.values.find(val => val.selected)
  46.     if (selectedVal) {
  47.       selectedArr[index] = selectedVal.name
  48.     } else {
  49.       selectedArr[index] = undefined
  50.     }
  51.   })
  52.   return selectedArr
  53. }
  54. // 更新按钮的禁用状态
  55. const updateDisabledStatus = (specs, pathMap) => {
  56.   // 遍历每一种规格
  57.   specs.forEach((item, i) => {
  58.     // 拿到当前选择的项目
  59.     const selectedArr = getSelectedArr(specs)
  60.     // 遍历每一个按钮
  61.     item.values.forEach(val => {
  62.       if (!val.selected) {
  63.         selectedArr[i] = val.name
  64.         // 去掉undefined之后组合成key
  65.         const key = selectedArr.filter(value => value).join(spliter)
  66.         val.disabled = !pathMap[key]
  67.       }
  68.     })
  69.   })
  70. }
  71. export default {
  72.   name: 'XtxGoodSku',
  73.   props: {
  74.     // specs:所有的规格信息  skus:所有的sku组合
  75.     goods: {
  76.       type: Object,
  77.       default: () => ({ specs: [], skus: [] })
  78.     }
  79.   },
  80.   emits: ['change'],
  81.   setup (props, { emit }) {
  82.     let pathMap = {}
  83.     watchEffect(() => {
  84.       // 得到所有字典集合
  85.       pathMap = getPathMap(props.goods.skus)
  86.       // 组件初始化的时候更新禁用状态
  87.       initDisabledStatus(props.goods.specs, pathMap)
  88.     })
  89.     const clickSpecs = (item, val) => {
  90.       if (val.disabled) return false
  91.       // 选中与取消选中逻辑
  92.       if (val.selected) {
  93.         val.selected = false
  94.       } else {
  95.         item.values.forEach(bv => { bv.selected = false })
  96.         val.selected = true
  97.       }
  98.       // 点击之后再次更新选中状态
  99.       updateDisabledStatus(props.goods.specs, pathMap)
  100.       // 把选择的sku信息传出去给父组件
  101.       // 触发change事件将sku数据传递出去
  102.       const selectedArr = getSelectedArr(props.goods.specs).filter(value => value)
  103.       // 如果选中得规格数量和传入得规格总数相等则传出完整信息(都选择了)
  104.       // 否则传出空对象
  105.       if (selectedArr.length === props.goods.specs.length) {
  106.         // 从路径字典中得到skuId
  107.         const skuId = pathMap[selectedArr.join(spliter)][0]
  108.         const sku = props.goods.skus.find(sku => sku.id === skuId)
  109.         // 传递数据给父组件
  110.         emit('change', {
  111.           skuId: sku.id,
  112.           price: sku.price,
  113.           oldPrice: sku.oldPrice,
  114.           inventory: sku.inventory,
  115.           specsText: sku.specs.reduce((p, n) => `${p} ${n.name}:${n.valueName}`, '').trim()
  116.         })
  117.       } else {
  118.         emit('change', {})
  119.       }
  120.     }
  121.     return { clickSpecs }
  122.   }
  123. }
  124. </script>
  125. <template>
  126.   <div class="goods-sku">
  127.     <dl v-for="item in goods.specs" :key="item.id">
  128.       <dt>{{ item.name }}</dt>
  129.       <dd>
  130.         <template v-for="val in item.values" :key="val.name">
  131.           <img :class="{ selected: val.selected, disabled: val.disabled }" @click="clickSpecs(item, val)"
  132.             v-if="val.picture" :src="val.picture" />
  133.           <span :class="{ selected: val.selected, disabled: val.disabled }" @click="clickSpecs(item, val)" v-else>{{
  134.               val.name
  135.           }}</span>
  136.         </template>
  137.       </dd>
  138.     </dl>
  139.   </div>
  140. </template>
  141. <style scoped lang="scss">
  142. @mixin sku-state-mixin {
  143.   border: 1px solid #e4e4e4;
  144.   margin-right: 10px;
  145.   cursor: pointer;
  146.   &.selected {
  147.     border-color: $xtxColor;
  148.   }
  149.   &.disabled {
  150.     opacity: 0.6;
  151.     border-style: dashed;
  152.     cursor: not-allowed;
  153.   }
  154. }
  155. .goods-sku {
  156.   padding-left: 10px;
  157.   padding-top: 20px;
  158.   dl {
  159.     display: flex;
  160.     padding-bottom: 20px;
  161.     align-items: center;
  162.     dt {
  163.       width: 50px;
  164.       color: #999;
  165.     }
  166.     dd {
  167.       flex: 1;
  168.       color: #666;
  169.       >img {
  170.         width: 50px;
  171.         height: 50px;
  172.         margin-bottom: 4px;
  173.         @include sku-state-mixin;
  174.       }
  175.       >span {
  176.         display: inline-block;
  177.         height: 30px;
  178.         line-height: 28px;
  179.         padding: 0 20px;
  180.         margin-bottom: 4px;
  181.         @include sku-state-mixin;
  182.       }
  183.     }
  184.   }
  185. }
  186. </style>
复制代码
这个就是index.vue的内容了。

  1. export default function bwPowerSet (originalSet) {
  2.   const subSets = []
  3.   // We will have 2^n possible combinations (where n is a length of original set).
  4.   // It is because for every element of original set we will decide whether to include
  5.   // it or not (2 options for each set element).
  6.   const numberOfCombinations = 2 ** originalSet.length
  7.   // Each number in binary representation in a range from 0 to 2^n does exactly what we need:
  8.   // it shows by its bits (0 or 1) whether to include related element from the set or not.
  9.   // For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
  10.   // include only "2" to the current set.
  11.   for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
  12.     const subSet = []
  13.     for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
  14.       // Decide whether we need to include current element into the subset or not.
  15.       if (combinationIndex & (1 << setElementIndex)) {
  16.         subSet.push(originalSet[setElementIndex])
  17.       }
  18.     }
  19.     // Add current subset to the list of all subsets.
  20.     subSets.push(subSet)
  21.   }
  22.   return subSets
  23. }
复制代码
这个是power-set.js的内容了。

在组件内调用一下它,注意要给它通报对象的。
它还会给父组件回传一个对象sku


如图,父组件内调用了这个子组件(sku)
子组件会界说了一些方法,会回传给父组件一个sku对象。

如图,写的很清晰。通报数据给父组件。
因为,我们的父组件,将来要写一个参加购物车的按钮 操作。需要用到这个sku(信息)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莫张周刘王

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表