前端商品SKU筛选如何实现?

如何根据 sku_list 里面的 quantity 库存来改变 spec_list 里面的 disabled
判断他是否可以选择;其中 sku_list 里面的 keys_idsspec_list 里面的 spec_id 关联的

这个是不是要用到 笛卡尔积算法 ?

image.png

<template>
    <div v-for="(item, index) in spec_list" :key="index" class="main">
        <p>{{item.title}}</p>
        <p>
            <spen v-for="(item2, index2) in item.children" :key="index2" :class="['main-item', {'active': item2.active, 'disabled': item2.disabled}]" @click="clickSpec(index, index2)">{{item2.title}}</spen>
        </p>
    </div>
    <div class="main" v-if="sku">{{sku}}</div>
</template>
<script>
import {computed, reactive} from "vue";

export default {
    setup() {

        const spec_list = reactive([{
            "title": "机型",
            "active": false,
            "disabled": false,
            "spec_id": "107",
            "parent_id": "0",
            "children": [{
                "title": "iPhone 14",
                "active": false,
                "disabled": false,
                "spec_id": "109",
                "parent_id": "107"
            }, {
                "title": "iPhone 14 Plus",
                "active": false,
                "disabled": false,
                "spec_id": "110",
                "parent_id": "107"
            }]
        }, {
            "title": "颜色",
            "active": false,
            "disabled": false,
            "spec_id": "108",
            "parent_id": "0",
            "children": [{
                "title": "蓝色",
                "active": false,
                "disabled": false,
                "spec_id": "111",
                "parent_id": "108"
            }, {
                "title": "紫色",
                "active": false,
                "disabled": false,
                "spec_id": "112",
                "parent_id": "108"
            }, {
                "title": "午夜色",
                "active": false,
                "disabled": false,
                "spec_id": "113",
                "parent_id": "108"
            }, {
                "title": "星光色",
                "active": false,
                "disabled": false,
                "spec_id": "114",
                "parent_id": "108"
            }, {
                "title": "红色",
                "active": false,
                "disabled": false,
                "spec_id": "115",
                "parent_id": "108"
            }]
        }, {
            "title": "存储容量",
            "active": false,
            "disabled": false,
            "spec_id": "116",
            "parent_id": "0",
            "children": [{
                "title": "128GB",
                "active": false,
                "disabled": false,
                "spec_id": "117",
                "parent_id": "116"
            }, {
                "title": "256GB",
                "active": false,
                "disabled": false,
                "spec_id": "118",
                "parent_id": "116"
            }, {
                "title": "512GB",
                "active": false,
                "disabled": false,
                "spec_id": "119",
                "parent_id": "116"
            }]
        }]);


        const sku_list = reactive([{
            "quantity": "0",
            "sku_id": "195",
            "keys_ids": "107:109;108:111;116:117",
        }, {
            "quantity": "100",
            "sku_id": "196",
            "keys_ids": "107:109;108:112;116:117",
        }, {
            "quantity": "0",
            "sku_id": "197",
            "keys_ids": "107:109;108:113;116:117",
        }, {
            "quantity": "100",
            "sku_id": "198",
            "keys_ids": "107:109;108:114;116:117",
        }, {
            "quantity": "100",
            "sku_id": "199",
            "keys_ids": "107:109;108:115;116:117",
        }, {
            "quantity": "100",
            "sku_id": "200",
            "keys_ids": "107:110;108:111;116:117",
        }, {
            "quantity": "100",
            "sku_id": "201",
            "keys_ids": "107:110;108:112;116:117",
        }, {
            "quantity": "100",
            "sku_id": "202",
            "keys_ids": "107:110;108:113;116:117",
        }, {
            "quantity": "100",
            "sku_id": "203",
            "keys_ids": "107:110;108:114;116:117",
        }, {
            "quantity": "100",
            "sku_id": "204",
            "keys_ids": "107:110;108:115;116:117",

        }, {
            "quantity": "100",
            "sku_id": "205",
            "keys_ids": "107:109;108:111;116:118",
        }, {
            "quantity": "100",
            "sku_id": "206",
            "keys_ids": "107:109;108:112;116:118",
        }, {
            "quantity": "100",
            "sku_id": "207",
            "keys_ids": "107:109;108:113;116:118",
        }, {
            "quantity": "100",
            "sku_id": "208",
            "keys_ids": "107:109;108:114;116:118",
        }, {
            "quantity": "100",
            "sku_id": "209",
            "keys_ids": "107:109;108:115;116:118",
        }, {
            "quantity": "100",
            "sku_id": "210",
            "keys_ids": "107:110;108:111;116:118",
        }, {
            "quantity": "100",
            "sku_id": "211",
            "keys_ids": "107:110;108:112;116:118",
        }, {
            "quantity": "100",
            "sku_id": "212",
            "keys_ids": "107:110;108:113;116:118",
        }, {
            "quantity": "100",
            "sku_id": "213",
            "keys_ids": "107:110;108:114;116:118",
        }, {
            "quantity": "100",
            "sku_id": "214",
            "keys_ids": "107:110;108:115;116:118",
        }, {
            "quantity": "100",
            "sku_id": "215",
            "keys_ids": "107:109;108:111;116:119",
        }, {
            "quantity": "100",
            "sku_id": "216",
            "keys_ids": "107:109;108:112;116:119",
        }, {
            "quantity": "100",
            "sku_id": "217",
            "keys_ids": "107:109;108:113;116:119",
        }, {
            "quantity": "100",
            "sku_id": "218",
            "keys_ids": "107:109;108:114;116:119",
        }, {
            "quantity": "100",
            "sku_id": "219",
            "keys_ids": "107:109;108:115;116:119",
        }, {
            "quantity": "100",
            "sku_id": "220",
            "keys_ids": "107:110;108:111;116:119",
        }, {
            "quantity": "100",
            "sku_id": "221",
            "keys_ids": "107:110;108:112;116:119",
        }, {
            "quantity": "100",
            "sku_id": "222",
            "keys_ids": "107:110;108:113;116:119",
        }, {
            "quantity": "100",
            "sku_id": "223",
            "keys_ids": "107:110;108:114;116:119",
        }, {
            "quantity": "100",
            "sku_id": "224",
            "keys_ids": "107:110;108:115;116:119",
        }]);

        const sku = computed(function () {
            const keys_ids = [];
            spec_list.forEach(function(val) {
                val.children.forEach(function(val2) {
                    if (val2.active) {
                        keys_ids.push(val.spec_id + ':' + val2.spec_id);
                    }
                });
            });
            return sku_list.find(o => o.keys_ids == keys_ids.join(';'));
        });

        const clickSpec = (index, index2) => {
            spec_list[index].children.forEach(function(val, i) {
                val.active = (!val.disabled && i == index2);
            });
        }

        return {spec_list, sku_list, sku, clickSpec}
    }
}
</script>

<style>
#preloader-active {
    display: none;
}

.main {
    width: 500px;
    margin: 30px auto;
}

.main-item {
    border: #ddd 1px solid;
    padding: 5px 10px;
    margin: 5px;
    display: inline-block;
    cursor: pointer;
}

.main-item:hover {
    border: #ef0909 1px solid;
}

.main-item.active {
    border: #ef0909 1px solid;
}

.main-item.disabled {
    border: #ddd 1px dashed;
}

.main-item.disabled:hover {
    border: #ddd 1px dashed;
}
</style>

https://sfc.vuejs.org/#eNrFWk...


一个朋友用库存的方法,解决了这个问题,备注一下:
https://sfc.vuejs.org/#eNrFWs...

<template>
    <div v-for="(item, index) in spec_list" :key="index" class="main">
        <p>{{item.title}}</p>
        <p>
            <spen v-for="(item2, index2) in item.children" :key="index2" :class="['main-item', {'active': item2.active, 'disabled': !countQuantity(item, item2)}]" @click="clickSpec(index, index2)">{{item2.title}}:{{countQuantity(item, item2)}}</spen>
        </p>
    </div>
    <div class="main" v-if="sku">{{sku}}</div>
</template>

<script>
import {computed, reactive} from "vue";

export default {
    name: "TestView",
    setup() {

        const spec_list = reactive([{
            "title": "机型",
            "active": false,
            "disabled": false,
            "spec_id": "107",
            "parent_id": "0",
            "children": [{
                "title": "iPhone 14",
                "active": false,
                "disabled": false,
                "spec_id": "109",
                "parent_id": "107"
            }, {
                "title": "iPhone 14 Plus",
                "active": false,
                "disabled": false,
                "spec_id": "110",
                "parent_id": "107"
            }]
        }, {
            "title": "颜色",
            "active": false,
            "disabled": false,
            "spec_id": "108",
            "parent_id": "0",
            "children": [{
                "title": "蓝色",
                "active": false,
                "disabled": false,
                "spec_id": "111",
                "parent_id": "108"
            }, {
                "title": "紫色",
                "active": false,
                "disabled": false,
                "spec_id": "112",
                "parent_id": "108"
            }, {
                "title": "午夜色",
                "active": false,
                "disabled": false,
                "spec_id": "113",
                "parent_id": "108"
            }, {
                "title": "星光色",
                "active": false,
                "disabled": false,
                "spec_id": "114",
                "parent_id": "108"
            }, {
                "title": "红色",
                "active": false,
                "disabled": false,
                "spec_id": "115",
                "parent_id": "108"
            }]
        }, {
            "title": "存储容量",
            "active": false,
            "disabled": false,
            "spec_id": "116",
            "parent_id": "0",
            "children": [{
                "title": "128GB",
                "active": false,
                "disabled": false,
                "spec_id": "117",
                "parent_id": "116"
            }, {
                "title": "256GB",
                "active": false,
                "disabled": false,
                "spec_id": "118",
                "parent_id": "116"
            }, {
                "title": "512GB",
                "active": false,
                "disabled": false,
                "spec_id": "119",
                "parent_id": "116"
            }]
        }]);


        const sku_list = reactive([{
            "quantity": "0",
            "sku_id": "195",
            "keys_ids": "107:109;108:111;116:117",
        }, {
            "quantity": "100",
            "sku_id": "196",
            "keys_ids": "107:109;108:112;116:117",
        }, {
            "quantity": "0",
            "sku_id": "197",
            "keys_ids": "107:109;108:113;116:117",
        }, {
            "quantity": "100",
            "sku_id": "198",
            "keys_ids": "107:109;108:114;116:117",
        }, {
            "quantity": "100",
            "sku_id": "199",
            "keys_ids": "107:109;108:115;116:117",
        }, {
            "quantity": "100",
            "sku_id": "200",
            "keys_ids": "107:110;108:111;116:117",
        }, {
            "quantity": "100",
            "sku_id": "201",
            "keys_ids": "107:110;108:112;116:117",
        }, {
            "quantity": "100",
            "sku_id": "202",
            "keys_ids": "107:110;108:113;116:117",
        }, {
            "quantity": "100",
            "sku_id": "203",
            "keys_ids": "107:110;108:114;116:117",
        }, {
            "quantity": "100",
            "sku_id": "204",
            "keys_ids": "107:110;108:115;116:117",

        }, {
            "quantity": "100",
            "sku_id": "205",
            "keys_ids": "107:109;108:111;116:118",
        }, {
            "quantity": "100",
            "sku_id": "206",
            "keys_ids": "107:109;108:112;116:118",
        }, {
            "quantity": "100",
            "sku_id": "207",
            "keys_ids": "107:109;108:113;116:118",
        }, {
            "quantity": "100",
            "sku_id": "208",
            "keys_ids": "107:109;108:114;116:118",
        }, {
            "quantity": "100",
            "sku_id": "209",
            "keys_ids": "107:109;108:115;116:118",
        }, {
            "quantity": "100",
            "sku_id": "210",
            "keys_ids": "107:110;108:111;116:118",
        }, {
            "quantity": "100",
            "sku_id": "211",
            "keys_ids": "107:110;108:112;116:118",
        }, {
            "quantity": "100",
            "sku_id": "212",
            "keys_ids": "107:110;108:113;116:118",
        }, {
            "quantity": "100",
            "sku_id": "213",
            "keys_ids": "107:110;108:114;116:118",
        }, {
            "quantity": "100",
            "sku_id": "214",
            "keys_ids": "107:110;108:115;116:118",
        }, {
            "quantity": "100",
            "sku_id": "215",
            "keys_ids": "107:109;108:111;116:119",
        }, {
            "quantity": "100",
            "sku_id": "216",
            "keys_ids": "107:109;108:112;116:119",
        }, {
            "quantity": "100",
            "sku_id": "217",
            "keys_ids": "107:109;108:113;116:119",
        }, {
            "quantity": "100",
            "sku_id": "218",
            "keys_ids": "107:109;108:114;116:119",
        }, {
            "quantity": "100",
            "sku_id": "219",
            "keys_ids": "107:109;108:115;116:119",
        }, {
            "quantity": "100",
            "sku_id": "220",
            "keys_ids": "107:110;108:111;116:119",
        }, {
            "quantity": "100",
            "sku_id": "221",
            "keys_ids": "107:110;108:112;116:119",
        }, {
            "quantity": "100",
            "sku_id": "222",
            "keys_ids": "107:110;108:113;116:119",
        }, {
            "quantity": "100",
            "sku_id": "223",
            "keys_ids": "107:110;108:114;116:119",
        }, {
            "quantity": "100",
            "sku_id": "224",
            "keys_ids": "107:110;108:115;116:119",
        }]);

        const active = {}

        const sku = computed(function () {
            const keys_ids = [];
            spec_list.forEach(function(val) {
                val.children.forEach(function(val2) {
                    if (val2.active) {
                        keys_ids.push(val.spec_id + ':' + val2.spec_id);
                    }
                });
            });
            return sku_list.find(o => o.keys_ids == keys_ids.join(';'));
        });

        const clickSpec = (index, index2) => {
            spec_list[index].children.forEach(function(val, i) {
                val.active = (!val.disabled && i == index2);
            });
            const item1 = spec_list[index];
            const item2 = item1.children[index2];
            active[item1.spec_id]=item2.spec_id;
        }

        const countQuantity = (item1, item2) => {
            const active2 = {...active, [item1.spec_id]:item2.spec_id}
            return sku_list.filter(sku=>{
                return spec_list.every(spec => {
                    const id1 = spec.spec_id
                    const id2 = active2[id1]
                    if (id2)return sku.keys_ids.split(';').includes([id1, id2].join(':'));
                    return true
                })
            }).reduce((r,sku)=>r+Number(sku.quantity), 0)
        }

        return {spec_list, sku_list, sku, clickSpec, countQuantity}
    }
}
</script>

<style>
#preloader-active {
    display: none;
}

.main {
    width: 500px;
    margin: 30px auto;
}

.main-item {
    border: #ddd 1px solid;
    padding: 5px 10px;
    margin: 5px;
    display: inline-block;
    cursor: pointer;
}

.main-item:hover {
    border: #ef0909 1px solid;
}

.main-item.active {
    border: #ef0909 1px solid;
}

.main-item.disabled {
    border: #ddd 1px dashed;
}

.main-item.disabled:hover {
    border: #ddd 1px dashed;
}
</style>

@无名 老大改的答案
https://sfc.vuejs.org/#__DEV_...

<template>
    <div v-for="(item, index) in spec_list" :key="index" class="main">
        <p>{{item.title}}</p>
        <p>
            <span v-for="(item2, index2) in item.children" :key="index2" :class="['main-item', {'active': active[item.spec_id] == item2.spec_id, 'disabled': !isSpecEnabled(item, item2)}]" @click="clickSpec(item, item2)">{{item2.title}}:{{countQuantity(item, item2)}}</span>
        </p>
    </div>
    <!-- <div class="main" v-if="sku">{{sku}}</div> -->
</template>
<script>
import {computed, reactive} from "vue";

export default {
    setup() {
        const spec_list = [{
            "title": "机型",
            "active": false,
            "disabled": false,
            "spec_id": "107",
            "parent_id": "0",
            "children": [{
                "title": "iPhone 14",
                "active": false,
                "disabled": false,
                "spec_id": "109",
                "parent_id": "107"
            }, {
                "title": "iPhone 14 Plus",
                "active": false,
                "disabled": false,
                "spec_id": "110",
                "parent_id": "107"
            }]
        }, {
            "title": "颜色",
            "active": false,
            "disabled": false,
            "spec_id": "108",
            "parent_id": "0",
            "children": [{
                "title": "蓝色",
                "active": false,
                "disabled": false,
                "spec_id": "111",
                "parent_id": "108"
            }, {
                "title": "紫色",
                "active": false,
                "disabled": false,
                "spec_id": "112",
                "parent_id": "108"
            }, {
                "title": "午夜色",
                "active": false,
                "disabled": false,
                "spec_id": "113",
                "parent_id": "108"
            }, {
                "title": "星光色",
                "active": false,
                "disabled": false,
                "spec_id": "114",
                "parent_id": "108"
            }, {
                "title": "红色",
                "active": false,
                "disabled": false,
                "spec_id": "115",
                "parent_id": "108"
            }]
        }, {
            "title": "存储容量",
            "active": false,
            "disabled": false,
            "spec_id": "116",
            "parent_id": "0",
            "children": [{
                "title": "128GB",
                "active": false,
                "disabled": false,
                "spec_id": "117",
                "parent_id": "116"
            }, {
                "title": "256GB",
                "active": false,
                "disabled": false,
                "spec_id": "118",
                "parent_id": "116"
            }, {
                "title": "512GB",
                "active": false,
                "disabled": false,
                "spec_id": "119",
                "parent_id": "116"
            }]
        }];

        const sku_list = [{
            "quantity": "0",
            "sku_id": "195",
            "keys_ids": "107:109;108:111;116:117",
        }, {
            "quantity": "100",
            "sku_id": "196",
            "keys_ids": "107:109;108:112;116:117",
        }, {
            "quantity": "0",
            "sku_id": "197",
            "keys_ids": "107:109;108:113;116:117",
        }, {
            "quantity": "100",
            "sku_id": "198",
            "keys_ids": "107:109;108:114;116:117",
        }, {
            "quantity": "100",
            "sku_id": "199",
            "keys_ids": "107:109;108:115;116:117",
        }, {
            "quantity": "100",
            "sku_id": "200",
            "keys_ids": "107:110;108:111;116:117",
        }, {
            "quantity": "100",
            "sku_id": "201",
            "keys_ids": "107:110;108:112;116:117",
        }, {
            "quantity": "100",
            "sku_id": "202",
            "keys_ids": "107:110;108:113;116:117",
        }, {
            "quantity": "100",
            "sku_id": "203",
            "keys_ids": "107:110;108:114;116:117",
        }, {
            "quantity": "100",
            "sku_id": "204",
            "keys_ids": "107:110;108:115;116:117",

        }, {
            "quantity": "100",
            "sku_id": "205",
            "keys_ids": "107:109;108:111;116:118",
        }, {
            "quantity": "100",
            "sku_id": "206",
            "keys_ids": "107:109;108:112;116:118",
        }, {
            "quantity": "100",
            "sku_id": "207",
            "keys_ids": "107:109;108:113;116:118",
        }, {
            "quantity": "100",
            "sku_id": "208",
            "keys_ids": "107:109;108:114;116:118",
        }, {
            "quantity": "100",
            "sku_id": "209",
            "keys_ids": "107:109;108:115;116:118",
        }, {
            "quantity": "100",
            "sku_id": "210",
            "keys_ids": "107:110;108:111;116:118",
        }, {
            "quantity": "100",
            "sku_id": "211",
            "keys_ids": "107:110;108:112;116:118",
        }, {
            "quantity": "100",
            "sku_id": "212",
            "keys_ids": "107:110;108:113;116:118",
        }, {
            "quantity": "100",
            "sku_id": "213",
            "keys_ids": "107:110;108:114;116:118",
        }, {
            "quantity": "100",
            "sku_id": "214",
            "keys_ids": "107:110;108:115;116:118",
        }, {
            "quantity": "100",
            "sku_id": "215",
            "keys_ids": "107:109;108:111;116:119",
        }, {
            "quantity": "100",
            "sku_id": "216",
            "keys_ids": "107:109;108:112;116:119",
        }, {
            "quantity": "100",
            "sku_id": "217",
            "keys_ids": "107:109;108:113;116:119",
        }, {
            "quantity": "100",
            "sku_id": "218",
            "keys_ids": "107:109;108:114;116:119",
        }, {
            "quantity": "100",
            "sku_id": "219",
            "keys_ids": "107:109;108:115;116:119",
        }, {
            "quantity": "100",
            "sku_id": "220",
            "keys_ids": "107:110;108:111;116:119",
        }, {
            "quantity": "100",
            "sku_id": "221",
            "keys_ids": "107:110;108:112;116:119",
        }, {
            "quantity": "100",
            "sku_id": "222",
            "keys_ids": "107:110;108:113;116:119",
        }, {
            "quantity": "100",
            "sku_id": "223",
            "keys_ids": "107:110;108:114;116:119",
        }, {
            "quantity": "100",
            "sku_id": "224",
            "keys_ids": "107:110;108:115;116:119",
        }];
      
          // 为了保证生成正则时的顺序,只能提前生成 {机型: null, 颜色: null, 容量: null} 了
        let active = reactive(Object.fromEntries(spec_list.map(i => [i.spec_id, null])));

        const clickSpec = ({spec_id: id1}, {spec_id: id2}) => {
          if (active[id1] != id2)
              active[id1] = id2;
          else
            active[id1] = null;
        };
        
        const isSpecEnabled = ({spec_id: id1}, {spec_id: id2}) => {
          return sku_list.filter(sku => sku.quantity > 0).some(sku => {
            const pattern = Object.entries(active).map(([k, v]) => k == id1 ? `${k}:${id2}` : v ? `${k}:${v}` : '.*').join(';');
            return sku.keys_ids.match(new RegExp('^' + pattern + '$'));
          })
        };
      
        const countQuantity = (item1, item2) => {
          const active2 = {...active, [item1.spec_id]: item2.spec_id}
          return sku_list.filter(sku => {
            const sku_keys_ids_array = sku.keys_ids.split(';');
            return spec_list.every(spec => {
              const id1 = spec.spec_id;
              const id2 = active2[id1];
              if (id2) return sku_keys_ids_array.includes([id1, id2].join(':'));
              return true
            })
          }).reduce((r, sku) => r + Number(sku.quantity), 0)
        };

        return {spec_list, sku_list, active, clickSpec, isSpecEnabled, countQuantity};
    }
}
</script>

<style>
.main {
    width: 500px;
    margin: 30px auto;
}

.main-item {
    border: #ddd 1px solid;
    padding: 5px 10px;
    margin: 5px;
    display: inline-block;
    cursor: pointer;
}

.main-item:hover {
    border: #ef0909 1px solid;
}

.main-item.active {
    border: #ef0909 1px solid;
}

.main-item.disabled {
    border: #ddd 1px dashed;
}

.main-item.disabled:hover {
    border: #ddd 1px dashed;
}
</style>
阅读 2.1k
2 个回答

前端新手来参与讨论。

感觉可用正则来确定是否有库存。

没有 vue.js,写了段 js 来模拟

功能

  1. 被选中的显示为 【名称】
  2. 有库存的显示为  名称 
  3. 没库存的显示为  ---- 

输出

机型:【iPhone 14】 iPhone 14 Plus 
颜色:【蓝色】 紫色  午夜色  星光色  红色 
存储容量: ----- 【256GB】 512GB 

js 代码

chosen = {107: 109, 108: 111, 116: 118};

console.log(spec_list.map(i =>
    i.title + ':' + i.children.map(j =>
        (chosen[i.spec_id] == j.spec_id ? '【-】' : ' - ').replace('-', sku_list.some(sku =>
            sku.keys_ids.match(new RegExp('^' + Object.entries(chosen).map(([k, v]) => k == i.spec_id ? `${k}:${j.spec_id}` : (v != null ? `${k}:${v}` : '.*')).join(';') + '$')) && sku.quantity > 0) ? j.title : '-'.repeat(j.title.length)
        )
    ).join('')
).join('\n'));

看不出来题主在纠结什么。

  1. 直接把两个数组合在一起,用来渲染
  2. 选择工具用 <input type="radio"> + <label>
  3. quantity 不够就 disabled
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
1 篇内容引用
推荐问题