美文网首页
基于Vue uniapp实现sku商品选择的规则

基于Vue uniapp实现sku商品选择的规则

作者: fordG | 来源:发表于2020-08-05 10:18 被阅读0次
  • 效果图 WFSuUMAIp6.gif
  • 参考代码iOS-SKU商品规格组合算法详解

  • 实现方式,利用卡迪尔坐标来匹配(所有可选项商品类别的坐标, 和商品类别可选条件坐标数组进行对比, 利用集合来获取可选商品类别)

*上代码

<template>
    <view style="padding-left: 40upx; padding-top: 50upx;">
        <view v-for="(spec, index) in phones.specList" class="row" :key="spec.title" v-if="showPage">
            <view style="font-size: 28upx; color: #333333;">{{spec.title}}</view>
            <view v-for="(item, i) in spec.list" :key="item.title" @click="itemClick(item, index)">
                <view :class="getItem(item)">{{item.title}}</view>
            </view>
        </view>

        <view v-if="sellCount != 0">{{'剩余: ' + sellCount + '\n选择商品条目id: ' + sellId}}</view>
    </view>
</template>

<script>
    export default {

        data() {
            return {
                phones: {
                    specList: [{
                            title: "颜色",
                            list: ["红色", "紫色"]
                        },
                        {
                            title: "套餐",
                            list: ["套餐一", "套餐二"]
                        },
                        {
                            title: "内存",
                            list: ["64G", "128G", "256G"]
                        },
                        {
                            title: "网络",
                            list: ["联通", "移动", "电信"]
                        },
                    ],
                    specCombinationList: [{
                            id: "1",
                            specs: ["紫色", "套餐一", "64G", "电信"],
                            count: 20
                        },
                        {
                            id: "2",
                            specs: ["紫色", "套餐一", "128G", "电信"],
                            count: 18
                        },
                        {
                            id: "3",
                            specs: ["紫色", "套餐二", "128G", "联通"],
                            count: 15
                        },
                        {
                            id: "4",
                            specs: ["红色", "套餐二", "256G", "移动"],
                            count: 10
                        }
                    ],
                },
                marryConditions: [], //匹配条件数组 specCombinationList里面的条件
                marryItems: {}, //匹配项 所有顶点集合
                set: null, //可选顶点集合
                alreadys: null, //放 已经选中了的顶点集合
                showPage: false,
                sellCount: 0,
                sellId: '',
            }
        },

        watch: {

        },

        created() {

            this.initData()
            this.showPage = true
        },

        methods: {
            //转换数据 设置坐标
            initData() {
                this.set = new Set()
                this.alreadys = new Set()
                this.phones.specList.forEach((spec, index) => {
                    spec.list.forEach((t, i) => {
                        var tmp = {
                            title: '',
                            point: {
                                x: 0,
                                y: index
                            }
                        }
                        tmp.point.x = i
                        tmp.title = t
                        spec.list[i] = tmp
                        this.marryItems[t] = tmp.point
                    })
                })
                /*
                         0    1   2
                    0    紫   红
                    
                    1    一   二
                    
                    2    64  128 256
                    (紫,二,256 [0, 1, 2])
                    (   二 point(1, 1) 用y = 1 取数组找下标1的值 = 1 存在
                        一 point(0, 1) y = 1 下标1 = 1 不存在
                        红 point(1, 0) y = 0 下标0 = 0 不存在
                        紫 point(0, 0) y = 0 下标0 = 0 存在
                       128 point(1, 2) y = 2 下标2 = 2 不存在
                    )
                */
                //取x, 用y取匹配( 取y用x好像无法匹配 )
                this.phones.specCombinationList.forEach((spec, index) => {
                    var arr = []
                    spec.specs.forEach(e => {
                        if (this.marryItems.hasOwnProperty(e)) {
                            arr.push(this.marryItems[e].x)
                        }
                    })
                    this.marryConditions.push(arr)
                })
            },

            itemClick(item, index) {
                // 选中的顶点不在可选顶点中,不可选
                if (!this.set._empty()) {
                    if (!this.set.has(item.title)) {
                        console.log('不可选')
                        return
                    }
                }
                //判断是否有相同类目的顶点
                let sameTop = this.hasSameTop(item)
                if(sameTop){
                    //有相同类目的顶点
                    this.deleteSameTop(item)
                }else{
                    // 没有相同类目的顶点直接加入集合
                    this.alreadys.add(item)
                }
                
                this.alreadys._log()
                this.set.clear()

                //迭代所有的条件, 同时满足alreadys里面的顶点的交集
                var tmpSet = new Set()
                this.marryConditions.forEach((arr, index) => {
                    var b = true
                    this.alreadys.forEach(already => {
                        if (arr[already.point.y] != already.point.x) {
                            b = false
                        }
                    })
                    if (b) {
                        let tmpSet = new Set(this.phones.specCombinationList[index].specs)
                        this.set = new Set([...this.set, ...tmpSet])
                        tmpSet = new Set([...this.set, ...tmpSet])
                    }

                })
                
                //判断如果只有一个类目的顶点, 要把该类目的所有顶点都加到集合中
                if (this.alreadys._length() == 1) {
                    let tmpItem = this.alreadys._findIndex(0)
                    this.phones.specList[tmpItem.point.y].list.forEach(e=>{
                        this.set.add(e.title)
                    })
                }
                
                //是否选择完成
                if (this.alreadys._length() == this.phones.specList.length) {
                    //选择完成, 获取剩余数量显示出来
                    this.calculateSellCount()
                } else {
                    this.sellCount = 0
                }
            },
            
            //是否有相同的顶点
            hasSameTop(item){
                var flag = false
                this.alreadys.forEach(e=>{
                    if(e.point.y == item.point.y){
                        flag = true
                    }
                })
                return flag
            },
            
            deleteSameTop(item){
                //如果有相同类目的顶点
                if(this.alreadys.has(item)){
                    //选择的同一个顶点
                    this.alreadys.delete(item)
                }else{
                    //选择同一个类目不同的顶点, 先清空集合内同一个类目的顶点, 在加入选中的顶点
                    this.alreadys.forEach(e=>{
                        if(e.point.y == item.point.y){
                            this.alreadys.delete(e)
                        }
                    })
                    this.alreadys.add(item)
                }
            },

            calculateSellCount() {
                this.marryConditions.forEach((arr, index) => {
                    var b = true
                    this.alreadys.forEach(already => {
                        if (arr[already.point.y] != already.point.x) {
                            b = false
                        }
                    })
                    if (b) {
                        this.sellCount = this.phones.specCombinationList[index].count
                        this.sellId = this.phones.specCombinationList[index].id
                    }

                })
            },

            alreadysTitle() {
                var set = new Set()
                this.alreadys.forEach(e => {
                    set.add(e.title)
                })
                return set
            },

            getItem(item) {
                // this.set._log()
                // this.alreadysTitle()._log()
                let title = item.title
                var c;
                if (this.alreadysTitle().has(title)) {
                    c = 'item_select'
                } else {
                    if (this.set._empty()) {
                        c = 'item'
                    } else if (this.set.has(title)) {
                        c = 'item'
                    } else {
                        c = 'item_disable'
                    }
                }
                // console.log(c)
                return c
            }
        },


    }
</script>

<style scoped>
    .row {
        display: flex;
        flex-direction: row;
        align-items: center;
        margin-top: 30upx;
    }

    .item {
        height: 30upx;
        padding: 20upx;
        border-style: solid;
        border-width: 1upx;
        border-color: #EEEEEE;
        color: #333333;
        font-size: 28upx;
        text-align: center;
        margin-left: 40upx;
    }

    .item_select {
        height: 30upx;
        padding: 20upx;
        border-style: solid;
        border-width: 1upx;
        border-color: red;
        color: red;
        font-size: 28upx;
        text-align: center;
        margin-left: 40upx;
    }

    .item_disable {
        height: 30upx;
        padding: 20upx;
        border-style: solid;
        border-width: 1upx;
        border-color: #999999;
        color: #999999;
        font-size: 28upx;
        text-align: center;
        margin-left: 40upx;
    }
</style>

  • proprety
Set.prototype._log = function (){
    var str = ''
    this.forEach(e=>{
        str += (JSON.stringify(e) + '\n')
    })
    console.log(str)
}

Set.prototype._empty = function (){
    var count = 0
    this.forEach(e=>{
        count++
    })
    return count == 0
}

Set.prototype._length = function (){
    var count = 0
    this.forEach(e=>{
        count++
    })
    return count
}

Set.prototype._findIndex = function (index){
    var arr = Array.from(this)
    var obj
    arr.forEach((e, i)=>{
        if(i == index){
            obj = e
        }
    })
    return obj
}

相关文章

网友评论

      本文标题:基于Vue uniapp实现sku商品选择的规则

      本文链接:https://www.haomeiwen.com/subject/fvzlrktx.html