耀实惠小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

237 lines
7.0 KiB

<template>
<u-popup mode="bottom" v-model="specShow" closeable border-radius="40" height="70%" @close="hide">
<view class="spec-popup h-100">
<view class="spec-popup-header position-fixed top-0 left-0 vw-100 bg-white p-20 flex align-end">
<view class="m-r-20">
<image class="spec-popup-header-image" :src="image == ''?goodsDetail.pic[0]:image" mode="aspectFit"></image>
</view>
<text class="text-red font-40" v-if="price">{{ price }} {{ goodsType == 'integralStore' ? '兑购' : '元' }}</text>
</view>
<view class="spec-popup-container">
<view class="m-b-20">
<view class="spec-popup-item" v-for="(item, index) in specList" :key="index">
<view class="spec-popup-item-title text-grey font-32 m-b-20">{{ item.title }}</view>
<view class="flex flex-wrap">
<view v-for="(attribute, attributeIndex) in item.list" :key="attributeIndex" :class="[
'spec-popup-item-suk',
selectSpec[item.title] === attribute.name ? 'spec-popup-item-suk--active' : '' ,
attribute.able ? '' : 'spec-popup-item-suk--disabled'
]" @click="changeSpec(item.title, attribute.name, attribute.able)">
{{ attribute.name }}
</view>
</view>
</view>
</view>
<view class="spec-popup-number flex align-center justify-between">
<text class="font-32 text-black">数量</text>
<u-number-box :min="goodsDetail.sumShop" :max="goodsDetail.stock" v-model="sukNum"></u-number-box>
</view>
</view>
<view class="spec-popup-confirm bg-white position-fixed bottom-0 left-0 vw-100 flex align-center justify-center">
<view class="spec-popup-confirm-btn">
<u-button shape="circle" type="primary" class='btn' @click="$u.debounce(addShopping, 500)">确定</u-button>
</view>
</view>
</view>
</u-popup>
</template>
<script>
import { IMG_URL } from '@/env.js'
export default {
props: {
goodsDetail: {
typeof: Object,
default: () => {}
},
},
data () {
return {
IMG_URL,
specShow: false,
specList: [], // property 列表
skuList: [], // sku 列表
selectSpec: {}, // 选择数据的对象
sukNum: 1,
price: 0,
type: '',
goodsType: '',
image:''
}
},
methods: {
show (bool, type, goodsType) {
this.type = type
this.goodsType = goodsType
this.specShow = bool;
if (bool) {
this.sukNum = this.goodsDetail.sumShop
let specList = JSON.parse(JSON.stringify(this.goodsDetail.attributeListVo))
this.skuList = this.goodsDetail.skuListSku;
// 初始化选择数据的对象
specList.forEach(item => {
this.$set(this.selectSpec, item.title, "");
})
// 将规格数据处理成我们视图所需要的数据类型
this.specList = specList.map(item => {
return {
title: item.title,
list: item.list.map(its => {
return {
name: its,
// 判断是否可以选择
able: this.isAble(item.title, its)
}
})
}
})
}
},
hide () {
this.specShow = false
this.type = ''
this.$emit('close')
},
// 核心判断逻辑
// 判断规格是否可以被选择 核心函数 key当前的规格的title value规格值
isAble(key, value) {
// 深拷贝 避免被影响
let copySelectSpec = JSON.parse(JSON.stringify(this.selectSpec));
// 用对象的好处就在这了 直接赋值当前验证项
copySelectSpec[key] = value;
// console.log(copySelectSpec, key, value)
// 用数组的 some 方法 效率高 符合条件直接退出循环
let flag = this.skuList.some(item => {
// 条件判断 核心逻辑判断
let i = 0;
// 这个for in 循环的逻辑就对底子不深的人来说就看不懂了 原理就是循环已经选中的 和 正在当前对比的数据 和 所有的sku对比 只有当前验证的所有项满足sku中的规格或者其他规格为空时 即满足条件 稍微有点复杂 把注释的调试代码打开就调试下就可以看懂了
for (let k in copySelectSpec) {
// console.log(copySelectSpec[k]) // 注释的调试看逻辑代码
if (copySelectSpec?.[k] && item.list.includes(copySelectSpec[k])) {
// console.log(item)
i++
} else if (copySelectSpec[k] == "") {
i++;
}
}
// 符合下面条件就退出了 不符合会一直循环知道循环结束没有符合的条件就 return false 了
return i == this.goodsDetail.attributeListVo.length
})
return flag
},
// 点击事件
changeSpec(key, value, able) {
if (!able) return
let flag = true
if (this.selectSpec[key] === value) {
this.selectSpec[key] = ''
} else {
this.selectSpec[key] = value
}
for (let key in this.selectSpec) {
if (!this.selectSpec[key]) flag = false
}
if (flag) {
// // debugger
this.skuList.forEach(item => {
let arr = Object.values(this.selectSpec)
if (arr.toString() === item.list.toString()) this.price = item.price
if (arr.toString() === item.list.toString()) this.image = item.image
})
// for (let i = 0; i < this.skuList.length; i++) {
// let item = this.skuList[i]
// let bool = true
// for (var j = 0; j < item.list.length; j++) {
// let subItem = item.list[j]
// bool = true
// console.log('0000000000')
// if (!this.selectSpec.hasOwnProperty(subItem)) {
// bool = false
// break
// }
// }
// console.log(subItemm,this.selectSpec, bool)
// if (bool) {
// this.price = item.price
// break
// }
// }
}
console.log(flag)
// forEach循环改变原数组
this.specList.forEach(item => {
item.list.forEach(its => {
its.able = this.isAble(item.title, its.name);
});
});
},
addShopping () {
this.$emit('addShopping', {num: this.sukNum, price: this.price, spec: this.selectSpec}, this.type)
}
}
}
</script>
<style lang="scss" scoped>
.spec-popup {
&-header {
height: 200rpx;
box-sizing: border-box;
&-image {
width: 160rpx;
height: 160rpx;
}
}
&-container {
padding: 220rpx 40rpx 120rpx;
}
&-item {
&-suk {
height: 60rpx;
border: 2rpx solid transparent;
border-radius: 34rpx;
margin-right: 40rpx;
padding: 0 30px;
margin-bottom: 20rpx;
font-size: 32rpx;
color: #000;
background: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
&--active {
border-color: $u-type-primary;
color: $u-type-primary;
background: #EEFCFF;
}
&--disabled {
opacity: 0.5;
border-color: #e0e0e0;
color: #999999;
}
}
}
&-confirm {
height: 100rpx;
&-btn {
width: 90%;
height: 80rpx;
/deep/ .btn{
button{
font-size: 36rpx;
}
}
}
}
}
//数量组件样式调整
</style>