|
|
- <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>
|