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/
赞赏
微信赞赏
支付宝赞赏
发表评论