zoukankan      html  css  js  c++  java
  • 前端如何展示商品属性:SKU多维属性状态判断算法的应用-Vue 实现

    由于公司开发了一个电商项目,涉及到前台商品属性的展示,所以百度上找了一下!找到了 周琪力写的一个算法例子,因为作者只有jQuery 实现demo, 自己仿照 demo 实现了一个 vue 的!

    周琪力原文: http://mp.weixin.qq.com/s?__biz=MzIwNjQwMzUwMQ==&mid=2247484853&idx=1&sn=bed59c1d83c3aeb4bf7881be8dbdd917&chksm=97236777a054ee61fc3cef07eb4b164fa28e26917ce0a409d876964ad3c2ee3f90a000e29beb#rd

    原文的demo实现:http://codepen.io/keelii/pen/RoOzgb

    效果图: 
    这里写图片描述

    附上代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Vue 实现商品属性的计算显示</title>
        <style>
            body {
                font-size: 12px;
            }
            dt {
                 100px;
                text-align: right;
            }
            dl {
                clear: both;
                overflow:hidden;
            }
            dl.hl {
                background:#ddd;
            }
            dt, dd {
                float:left;
                height: 40px;
                line-height: 40px;
                margin-left: 10px;
            }
            button {
                font-size: 14px;
                font-weight: bold;
                 100px;
                height: 30px;
                margin: 0 10px;
            }
    
            .disabled {
                color:#999;
                border: 1px dashed #666;
            }
            .active {
                color: red;
            }
    
            .top-but {
                margin: 10px;
            }
    
            #skuId {
                height: 24px;
                font-size: 14px;
                line-height: 24px;
            }
        </style>
    </head>
    <body>
        <textarea id="values" style="600px;height:100px">
            [
               { "颜色": "红", "尺码": "大", "型号": "A", "skuId": "3158055" },
               { "颜色": "白", "尺码": "大", "型号": "A", "skuId": "3158054" },
               { "颜色": "白", "尺码": "中", "型号": "B", "skuId": "3133859" },
               { "颜色": "蓝", "尺码": "小", "型号": "C", "skuId": "3516833" }
            ]
        </textarea>
        <div id="app">
            <label> 
                默认选中 :  
                <input type="text" name="skuId" id="skuId" v-bind:value="skuId">
            </label>
            <button @click="getTextareaData" class="top-but"> 重新加载数据 </button> 当前属性ID:{{ skuId }}
            <dl v-for="item, key in list.result" class="content" v-bind:class="{hl: highKeys[key]}">
                <dt> {{key}} : </dt> 
                <dd>
                    <button
                        class="item"
                        v-for="value in item"
                        @click="handleActive(key, value)"
                        v-bind:class="{active: value.active, disabled: !value.active && value.disabled}" 
                        > {{ value.name }} </button> 
                </dd>
            </dl>
            已经选择:{{ message }}
        </div>
    </body>
    <script src="https://unpkg.com/vue "></script>
    <script>
        let vue = new Vue({
            el: "#app",
            data(){
                return {
                    data: [],
                    skuId: "",
                    skuName: "skuId",
                    // 属性名称信息
                    keys: [],
                    // 数据集合{list.result list.items}
                    list: {},
                    // 分隔符
                    spliter: 'u2299',
                    result: {},
                    message: "",
                    highKeys: {},
                };
            },
            methods: {
                powerset(arr) {
                    let ps = [[]];
                    for (let i = 0; i < arr.length; i++) {
                        for (let j = 0, len = ps.length; j < len; j++) {
                            ps.push(ps[j].concat(arr[i]));
                        }
                    }
    
                    return ps;
                },
    
                /**
                 * 初始化数据
                 * @return 
                 */
                initData() {
                    this.result = {};
                    this.keys = this.getAllKeys();
                    for (let i = 0; i < this.keys.length; i ++) {
                        this.highKeys[this.keys[i]] = false;
                    }
    
                    this.list = this.combineAttr(this.data, this.keys);
                    this.initSeleted(this.skuId);
                    this.buildResult(this.list.items)
                    this.updateStatus(this.getSelectedItem());
                    this.showResult();
                },
    
                /**
                 * 获取输入表单中的数据进行初始化
                 * @return
                 */
                getTextareaData() {
                    let data = document.getElementById('values').value;
                    let skuId = document.getElementById("skuId").value;
    
                    try {
                        this.data = JSON.parse(data);
                        let isHas = false;
                        for (let i = 0; i < this.data.length; i ++) {
                            if (skuId == this.data[i][this.skuName]) {
                                isHas = true;
                                break
                            }
                        }
    
                        this.skuId = isHas ? skuId : this.data[0][this.skuName];
                        this.initData();
                    } catch (e) {
                        this.data = [];
                    }
                },
    
                /**
                 * 正常属性点击
                 */
                handleNormalClick(key, value) {
                    for (let i in this.list.result[key]) {
                        if (i != value.name) {
                            this.list.result[key][i].active = false;
                        } else {
                            this.list.result[key][i].active = true;
                        }
                    }
                },
    
                /**
                 * 无效属性点击
                 */
                handleDisableClick(key, value) {
                    this.list.result[key][value.name]["disabled"] = false;
                    // 清空高亮行的已选属性状态(因为更新的时候默认会跳过已选状态)
                    for (let i in this.list.result) {
                        if (i != key) {
                            for (let x in this.list.result[i]) {
                                this.list.result[i][x].active = false;
                            }
                        }
                    }
    
                    this.updateStatus(this.getSelectedItem());
                },
    
                /**
                 * 高亮行
                 */
                highAttributes: function() {
                    for (let key in this.list.result) {
                        this.highKeys[key] = true;
                        for (let attr in this.list.result[key]) {
                            if (this.list.result[key][attr].active === true) {
                                this.highKeys[key] = false;
                                break;
                            }
                        }
                    }
                },
    
                /**
                 * 点击事件处理
                 * @param  key   点击的行
                 * @param  value 点击的按钮的数据
                 */
                handleActive: function(key, value) {
                    if (value.active == true) {
                        return false;
                    }
    
                    this.handleNormalClick(key, value);
                    if (value.disabled === true) {
                        this.handleDisableClick(key, value);
                    }
    
                    this.updateStatus(this.getSelectedItem());
                    this.highAttributes();
                    this.showResult();
                },
    
                /**
                 * 计算属性
                 * @param  {[type]} data [description]
                 * @param  {[type]} keys [description]
                 * @return {[type]}      [description]
                 */
                combineAttr(data, keys) {
                    let allKeys = []
                    let result = {}
    
                    for (let i = 0; i < data.length; i++) {
                        let item = data[i]
                        let values = []
    
                        for (let j = 0; j < keys.length; j++) {
                            let key = keys[j]
                            if (!result[key]) {
                                result[key] = {};
                            }
    
                            if (!result[key][item[key]]) {
                                result[key][item[key]] = {"name": item[key], "active": false, "disabled": true};
                            }
    
                            values.push(item[key]);
                        }
    
                        allKeys.push({
                            path: values.join(this.spliter),
                            sku: item['skuId']
                        });
                    }
    
                    return {
                        result: result,
                        items: allKeys
                    }
                },
    
                /**
                 * 获取所有属性
                 * @return {[type]} [description]
                 */
                getAllKeys() {
                    let arrKeys = [];
                    for (let attribute in this.data[0]) {
                        if (!this.data[0].hasOwnProperty(attribute)) {
                            continue;
                        } 
    
                        if (attribute !== this.skuName) {
                            arrKeys.push(attribute);
                        }
                    }
    
                    return arrKeys;
                },
    
                getAttruites(arr) {
                    let result = []
                    for (let i = 0; i < arr.length; i++) { 
                        result.push(arr[i].path) 
                    }
    
                    return result
                },
    
                /**
                 * 生成所有子集是否可选、库存状态 map
                 */
                buildResult(items) {
                    let allKeys = this.getAttruites(items)
    
                    for (let i = 0; i < allKeys.length; i++) {
                        let curr = allKeys[i];
                        let sku = items[i].sku;
                        let values = curr.split(this.spliter);
                        let allSets = this.powerset(values);
    
                        // 每个组合的子集
                        for (let j = 0; j < allSets.length; j++) {
                            let set = allSets[j]
                            let key = set.join(this.spliter)
    
                            if (this.result[key]) {
                                this.result[key].skus.push(sku)
                            } else {
                                this.result[key] = {
                                    skus: [sku]
                                }
                            }
                        }
                    }
                },
    
                /**
                 * 获取选中的信息
                 * @return Array 
                 */
                getSelectedItem() {
                    let result = [];
                    for (let attr in this.list.result) {
                        let attributeName = '';
                        for (let attribute in this.list.result[attr]) {
                            if (this.list.result[attr][attribute].active === true) {
                                attributeName = attribute;
                            }
                        }
    
                        result.push(attributeName);
                    }
    
                    return result
                },
    
                /**
                 * 更新所有属性状态
                 */
                updateStatus(selected) {
                    for (let i = 0; i < this.keys.length; i++) {
                        let key = this.keys[i],
                            data = this.list.result[key],
                            hasActive = !!selected[i],
                            copy = selected.slice();
    
                        for (let j in data) {
                            let item = data[j]["name"];
                            if (selected[i] == item) {
                                continue
                            }
    
                            copy[i] = item
                            let curr = this.trimSpliter(copy.join(this.spliter), this.spliter);
                            this.list.result[key][j]["disabled"]  = this.result[curr] ? false : true;
                        }
                    }
                },
    
                trimSpliter(str, spliter) {
                    // ⊙abc⊙ => abc
                    // ⊙a⊙⊙b⊙c⊙ => a⊙b⊙c
                    let reLeft    = new RegExp('^' + spliter + '+', 'g');
                    let reRight   = new RegExp(spliter + '+$', 'g');
                    let reSpliter = new RegExp(spliter + '+', 'g');
                    return str.replace(reLeft, '')
                        .replace(reRight, '')
                        .replace(reSpliter, spliter)
                },
    
                /**
                 * 初始化选中
                 * @param  mixed|Int|String skuId 需要选中的skuId
                 * @return {[type]}       [description]
                 */
                initSeleted(skuId) {
                    for (let i in this.data) {
                        if (this.data[i][this.skuName] == skuId) {
                            for (let x in this.data[i]) {
                                if (x !== this.skuName) {
                                    this.list.result[x][this.data[i][x]].active = true;
                                }
                            }
                            break;
                        }
                    }
                },
    
                /**
                 * 显示选中的信息
                 * @return 
                 */
                showResult() {
                    let result = this.getSelectedItem()
                    let s = []
                    for (let i = 0; i < result.length; i++) {
                        let item = result[i];
                        if (!!item) {
                            s.push(item)
                        }
                    }
    
                    if (s.length == this.keys.length) {
                        let curr = this.result[s.join(this.spliter)]
                        if (curr) {
                            s = s.concat(curr.skus)
                            this.skuId = curr.skus[0];
                        }
    
                        this.message = s.join('u3000-u3000');
                    }
                }
            },
    
            created() {
                this.getTextareaData();
            }
        })
    </script>
    </html>
  • 相关阅读:
    python dataformat.py通用数据格式转化脚本
    python ftp操作脚本&常用函数
    函数的作用域
    阶段规划
    Linux 远程登录Windows图形界面
    php常用的几个算法
    书目列表【当前&后续】
    提高工作效率的工具[分享]
    浏览器的调试软件
    Linux回收站[改写rm防止误删文件无法恢复]
  • 原文地址:https://www.cnblogs.com/xiaocaiyuxiaoniao/p/9790764.html
Copyright © 2011-2022 走看看