vue实现电商网站购物车sku多规格选择
最近的项目中因为对接京东接口,需要用到多规格选择,网上找了不少案例教程但是大部分要么不满足需求要么就是存在bug,最终还是找到了一个可以符合使用要求的样本,然后就改编了下交给开发同学再去优化实现了。先看效果(支持动态规格及规格个数,如果规格及sku不是很多的话前端计算应该还是没问题的,如果你非要搞几十、几百的规格和sku来测试 那可能会有点卡顿):
下面是主要vue文件实现逻辑代码,具体实现看代码说明吧,可以自行创建一个vue2项目然后引入newSkuTwo.vue来使用。
newSkuTwo.vue
<!-- Use preprocessors via the lang attribute! e.g. <template lang="pug"> --> <template> <div > <div id="sku" v-if="key.length>0" v-for="(keyItem,index) in key"> <div class="title">规格维度-{{keyItem.name}} :</div> <div v-for="(label,sort) in keyItem.item" :class="['label-info', {'selected':keyItem.itemIndex===sort}]" style="display: inline-block;"> <button @click="toggeItem(index, sort)" :disabled="!checkSku(label,index)" :class="{disabled: !checkSku(label,index)}"> <img v-if="keyItem.itemImage[sort].length>0" :src=keyItem.itemImage[sort] :class="['label_img']"/> {{label}}</button> </div> </div> <div id="result" v-if="result"> <div>假库存:{{result.count}}</div> <div>假价格:{{result.price}}</div> <div>skuid:{{result.skuid}}</div> <div><img :src=result.imagePath style="width:200px;" /></div> </div> <div style="margin-top:1px;" :class="{'selected':canBuy===0}"> <button @click="toggleDialog('dialogVisible', false)">关闭本页</button> <button @click="myChoose(result)">{{canBuy===0?"请选择规格":"加入购物车"}}</button> </div> </div> </template> <script> import axios from 'axios'; export default { props: { visible: Boolean, skuId9:String, skuInfo:String }, data(){ return{ message: 'Hello Vue!', canBuy:0, key:[], sku:{}, skuDetail:{ "sku": { "新【小米平板6】远山蓝;8+256GB/144Hz/2.8K;官方标配": { "skuid": "100056375397", "price": 496, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+256GB/144Hz/2.8K;标准键盘套装": { "skuid": "100050512106", "price": 205, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+128GB/144Hz/2.8K;触控键盘+触控笔套装": { "skuid": "100057489095", "price": 194, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+256GB/144Hz/2.8K;触控笔套装": { "skuid": "100050512090", "price": 189, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+128GB/144Hz/2.8K;标准键盘套装": { "skuid": "100057489061", "price": 160, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+128GB/144Hz/2.8K;官方标配": { "skuid": "100048837216", "price": 315, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+256GB/144Hz/2.8K;触控键盘+触控笔套装": { "skuid": "100050512182", "price": 281, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+128GB/144Hz/2.8K;触控键盘套装": { "skuid": "100057489145", "price": 244, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+256GB/144Hz/2.8K;触控键盘套装": { "skuid": "100050512116", "price": 215, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;8+128GB/144Hz/2.8K;触控笔套装": { "skuid": "100057489113", "price": 212, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】远山蓝;6+128GB/144Hz/2.8K;官方标配": { "skuid": "100048837194", "price": 293, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;6+128GB/144Hz/2.8K;触控键盘+触控笔套装": { "skuid": "100050512078", "price": 177, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+128GB/144Hz/2.8K;触控键盘套装": { "skuid": "100057489079", "price": 178, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+256GB/144Hz/2.8K;触控笔套装": { "skuid": "100057489143", "price": 242, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+128GB/144Hz/2.8K;标准键盘套装": { "skuid": "100050512074", "price": 173, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+256GB/144Hz/2.8K;标准键盘套装": { "skuid": "100057489077", "price": 176, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+256GB/144Hz/2.8K;官方标配": { "skuid": "100048837232", "price": 331, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+128GB/144Hz/2.8K;官方标配": { "skuid": "100048837214", "price": 313, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+256GB/144Hz/2.8K;触控键盘套装": { "skuid": "100050512100", "price": 199, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+256GB/144Hz/2.8K;触控键盘+触控笔套装": { "skuid": "100050512094", "price": 193, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;6+128GB/144Hz/2.8K;官方标配": { "skuid": "100048837218", "price": 317, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;6+128GB/144Hz/2.8K;标准键盘套装": { "skuid": "100050512152", "price": 251, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+128GB/144Hz/2.8K;触控键盘+触控笔套装": { "skuid": "100057489067", "price": 166, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;6+128GB/144Hz/2.8K;触控键盘套装": { "skuid": "100057489129", "price": 228, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;8+128GB/144Hz/2.8K;触控笔套装": { "skuid": "100057489103", "price": 202, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】金色;6+128GB/144Hz/2.8K;触控笔套装": { "skuid": "100050512176", "price": 275, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+256GB/144Hz/2.8K;触控笔套装": { "skuid": "100050512174", "price": 273, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+256GB/144Hz/2.8K;触控键盘套装": { "skuid": "100050512172", "price": 271, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+128GB/144Hz/2.8K;触控笔套装": { "skuid": "100050512140", "price": 239, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;6+128GB/144Hz/2.8K;官方标配": { "skuid": "100056375399", "price": 498, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+128GB/144Hz/2.8K;官方标配": { "skuid": "100056375377", "price": 476, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+256GB/144Hz/2.8K;标准键盘套装": { "skuid": "100057489065", "price": 164, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+128GB/144Hz/2.8K;标准键盘套装": { "skuid": "100050512148", "price": 247, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+256GB/144Hz/2.8K;官方标配": { "skuid": "100048837212", "price": 311, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+256GB/144Hz/2.8K;触控键盘+触控笔套装": { "skuid": "100057489085", "price": 184, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+128GB/144Hz/2.8K;触控键盘套装": { "skuid": "100050512112", "price": 211, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" }, "新【小米平板6】黑色;8+128GB/144Hz/2.8K;触控键盘+触控笔套装": { "skuid": "100050512080", "price": 179, "count": 1, "imagePath": "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" } }, "key": [{ "name": "颜色", "itemIndex": 1, "item": [ "新【小米平板6】远山蓝", "新【小米平板6】金色", "新【小米平板6】黑色" ], "imagePath": "", "itemImage": [ "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg", "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg", "//img13.360buyimg.com/n0/jfs/t1/135050/18/30124/71701/643e634eF33711340/1bcf1ef8286605b7.jpg" ] }, { "name": "存储", "itemIndex": 1, "item": [ "6+128GB/144Hz/2.8K", "8+128GB/144Hz/2.8K", "8+256GB/144Hz/2.8K" ], "imagePath": "", "itemImage": [ "", "", "" ] }, { "name": "套装组合", "itemIndex": 4, "item": [ "官方标配", "标准键盘套装", "触控笔套装", "触控键盘+触控笔套装", "触控键盘套装" ], "imagePath": "", "itemImage": [ "", "", "", "", "" ] } ], "code": 0 }, // 重新组合的sku数据 resultSKU: [] } },computed: { dialogVisible: { get() { return this.visible; }, set(val) { this.$emit('update:visible', val); }, }, }, mounted() { //this.getSkuDetailInfo('100005886305'); this.getSkuDetailInfo(this.skuInfo); //this.initSku(); }, methods: { initSku() { const sku = this.sku; let resultSKU = []; let skuKeys = this.getObjKeys(sku); for(let i in skuKeys) { let skuKey = skuKeys[i]; // 获取一条SKU的key let skuData = sku[skuKey]; //获取当前sku的数据 //console.log(skuData); let skuKeyAttrs = skuKey.split(';'); //获取当前sku的属性数组 let combArr = this.recombine(skuKeyAttrs); //获取当前sku拆分的组合数组 for(let j=0;j<combArr.length;j++) { let key = combArr[j].join(';'); if(resultSKU[key]) { resultSKU[key].count += skuData.count; resultSKU[key].price.push(skuData.price); resultSKU[key].skuid = skuData.skuid; } else { resultSKU[key] = { count: skuData.count, price: [skuData.price], skuid: skuData.skuid, imagePath:skuData.imagePath, } } } } this.showCountAndPrice(resultSKU);//初始化选择状态 // console.log(resultSKU, 'resultSKU'); this.resultSKU = resultSKU; }, recombine(arr) { const labelArr = arr; // 获取重新组合的数组格式 例如[['黑', ''],['16G', ''],['电信', '']] // 进行横向遍历,填充组合数组 const newLabelArr = labelArr.map((item) => [item, '']); // 进行横向遍历,填充组合数组,从0开始递归 let resultArr = this.getCombineArr(newLabelArr,0); return resultArr; }, getCombineArr(arr,index) { let resultArr = []; let newArr = []; const recursion = (arr,index) => { for(let i=0;i<arr[index].length;i++) { newArr[index] = arr[index][i]; if(index===(arr.length-1)) { resultArr.push(JSON.parse(JSON.stringify(newArr))); } else { // 递归 recursion(arr,index+1) } } } recursion(arr,index); return resultArr; }, // 获取对象key数组集合 getObjKeys(obj) { if(obj!==Object(obj)){ throw new TypeError('Invalid object!') } let keysArr = []; for(let key in obj) { if(Object.prototype.hasOwnProperty.call(obj, key)){ keysArr[keysArr.length] = key; } } return keysArr; }, toggeItem(index,sort) { if(this.key[index].itemIndex === sort) { this.key[index].itemIndex = -1; } else { this.key[index].itemIndex = sort; } this.showCountAndPrice(this.resultSKU); }, showCountAndPrice(skuData) { let skuLabelArr = []; let i=0; let j=0; this.key.forEach(element => { j++ const _index = element.itemIndex; //skuLabelArr.push(_index===-1?'':element.item[_index]); if (_index===-1){ i=i; //skuLabelArr.push(); }else{ i++;//计算已选 skuLabelArr.push(element.item[_index]); } }); if (i===j){ console.log('已选完'); this.canBuy=1; }else{ this.canBuy=0; } const skuLabel = skuLabelArr.join(';'); //console.log('11111'); //console.log(skuLabel); //console.log(skuData); //let all_num = this.key.length; //let selected_num = skuLabel.split(';') if(skuData[skuLabel]) { this.result = skuData[skuLabel]; const maxPrice = Math.max(...skuData[skuLabel].price); const minPrice = Math.min(...skuData[skuLabel].price); this.result = { count: skuData[skuLabel].count, price: maxPrice > minPrice ? minPrice + '-' + maxPrice : maxPrice, skuid:skuData[skuLabel].skuid, imagePath:skuData[skuLabel].imagePath } } else { this.result = null; } }, checkSku(str,index) { let choosedLabelArr = []; const key = this.key; key.forEach((item) => { choosedLabelArr.push(item.itemIndex>-1?item.item[item.itemIndex]:'') }); // 假设当前已选中 choosedLabelArr[index] = str; let nowChooseStr = choosedLabelArr.join(';'); // 遍历加工完的数据集,是否有库存可选,有就可点击,没有就禁用 let canChoose = false; const resultSKU = this.resultSKU; for(let skuLey in resultSKU) { if(skuLey.indexOf(nowChooseStr)>-1) { if(resultSKU[skuLey].count>0) { canChoose = true; break; } } } return canChoose; }, getSkuDetailInfo(skuId){ /* axios.get(`http://请求后台?action=skuInfoTb&skuId=`+skuId).then( res =>{ if ('code' in res.data && res.data.code !=0){ alert(JSON.stringify(res.data)); this.key=[]; this.sku={}; this.toggleDialog('dialogVisible', false); return false; } this.key=(res.data.key); this.sku=(res.data.sku); this.initSku(); //console.log(this.sku); //console.log(this.sku1); //提供数据:search组件要给list组件传递数据,就要触发list组件中的自定义事件并携带要传递的数据 //请求成功后更新list里面的数据 //this.$bus.$emit("updateListDate",{isLoading:false,errMsg:'',users:res.data.items}) }, error =>{ console.log("请求成功",error.message) //请求失败后更新list里面的数据 //this.$bus.$emit("updateListDate",{isLoading:false,errMsg:error.message,users:[]}) } )*/ this.key=(this.skuDetail.key); this.sku=(this.skuDetail.sku); this.initSku(); }, myChoose(s){ if(!s || this.canBuy==0){ alert('规格选择尚未结束!'); return false; } if(s.count<1){ alert('库存不足,请重新选择'); return false; } console.log('规格参数已选完'); alert('规格参数已选完'); /* axios.get(`http://查询接口?action=querySkuPrice&skuId=`+this.result.skuid).then( res =>{ alert("价格接口查询结果:"+JSON.stringify(res.data)); }, error =>{ } ) */ }, toggleDialog(key, visible) { this[key] = visible; } } }; </script> <!-- Use preprocessors via the lang attribute! e.g. <style lang="scss"> --> <style> .disabled { background-color: #ccc; } #sku { #display: flex; padding:20px; } .selected button{ color: red; } #app { font-family: Avenir, Helvetica, Arial, sans-serif; text-align: center; color: #2c3e50; margin-top: 60px; } .label-info { #padding: 5px; flex: 1; overflow: hidden; overflow-y: auto; } .label_img{ width:45px; } a, button { color: #4fc08d; } button { background: none; border: solid 1px; border-radius: 0.2em; font: inherit; margin:3px; padding: 0.5em 0.5em; } input{ background: none; border: solid 1px; border-radius: 0.2em; font: inherit; margin:3px; padding: 0.5em 0.5em; } </style>
App.vue
<template> <div id="app"> <div v-if="!visible"> <ul> <li>100057489079 <button type="primary" @click="handleClick('100057489079')">3个规格加强版示例</button></li> <li><input v-model="skuInfo" /> <button @click="handleClick(skuInfo)">打开指定skuId示例</button></li> </ul> </div> <new-sku-two v-if="visible" :visible.sync="visible" :skuInfo="skuInfo"/> <br>本代码改编自参考地址 https://blog.csdn.net/baidu_16839249/article/details/114370304#t4 </div> </template> <script> import newSkuTwo from '@/components/newSkuTwo.vue' import axios from 'axios'; export default { components: { newSkuTwo }, data(){ return{ showSkuSelect:false, showSkuButton:true, visible:false, skuId9:'', skuInfo:'100057489079' } }, methods:{ handleClick(val){ console.log('-->>',(val).toString()); this.skuInfo=val; this.visible=true; } } } </script>
改版后的源码可取仓库下载:https://github.com/joolan/sku-select-vue/
基于互联网精神,在注明出处的前提下本站文章可自由转载!
本文链接:https://ranjuan.cn/vue-sku-select/
赞赏
微信赞赏支付宝赞赏
发表评论