用于跟踪购物车可用性的Javascript数组/对象/哈希表

时间:2013-12-12 12:54:15

标签: javascript jquery

我不知道这是否可能,但似乎必须有一种更简单的方法来做到这一点。我目前有一个T恤商店的购物车。每件T恤在购买前都有3个下拉框供选择:

风格:

  • American Apparel
  • Gildan

尺寸:

  • 取值
  • 中号
  • XL

颜色

  • 黑色
  • 灰色

并非每种尺寸和颜色组合都可以使用每种款式,但除了购物车在页面上的布局方式外,用户没有固定的方式首先选择款式,然后在不强制它的情况下选择款式,这将是一个障碍出售。

现在,当用户从任何下拉框中选择任何内容时,会向服务器发出ajax调用以计算其他下拉框应包含的内容,例如,如果用户首先选择Size(L),颜色可能会变为蓝色和黑色,因为白色和灰色不适用于大号,但比白色可能更差,但只有吉尔丹风格。

无论如何,ajax调用具有延迟,并且在具有不稳定数据连接的移动设备上可能特别慢。有没有办法用Javascript来实现这个目的。我知道渲染页面之前的所有组合,我可以设置一个数组,但由于有两个以上的下拉框而丢失,最终导致这个丑陋的混乱,即便如此,我也不知道如何执行更改框的实际功能,因为可以选择多个框:

<html>
<head>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script>
        var styles = { aa: 'American Apparel', gi: 'Gildan' };
        var sizes = { s: 'Small', m: 'Medium', l: 'Large' };
        var colours = { blue: 'Blue', black: 'Black', white: 'White', grey: 'Grey' };

        var availability = {
            aa: { size: ['s', 'm', 'l'], colour: ['blue', 'black', 'white', 'grey'] },
            gi: { size: ['s', 'm'], colour: ['blue', 'black', 'white', 'grey'] },
            s: { style: ['aa', 'gi'], colour: ['blue', 'black', 'white'] },
            m: { style: ['aa', 'gi'], colour: ['black', 'white', 'grey'] },
            l: { style: ['aa'], colour: ['blue', 'black', 'white', 'grey'] },
            blue: { style: ['aa', 'gi'], size: ['s', 'l'] },
            black: { style: ['aa', 'gi'], size: ['s', 'm', 'l'] },
            white: { style: ['aa', 'gi'], size: ['s', 'm', 'l'] },
            grey: { style: ['aa', 'gi'], size: ['m', 'l'] }
        };

        $(function()
        {
            addOptions('style', styles);
            addOptions('size', sizes);
            addOptions('colour', colours);
        });

        function addOptions(name, data)
        {
            $('select[name="' + name + '"]').empty();

            $.each(data, function(value, description)
            {
                $('select[name="' + name + '"]').append('<option value="' + value + '">' + description + '</option>');
            });
        }

        function updateOptions(select)
        {
            // Work out what has changed, and update select boxes?
        }
    </script>
</head>
<body>
    <select name="style" onchange="updateOptions(this);"></select>
    <select name="size" onchange="updateOptions(this);"></select>
    <select name="colour" onchange="updateOptions(this);"></select>
</body>
</html>

使用更智能的功能和/或哈希表是否有更有效的方法?这些可能不是唯一的三个选项,例如商店也有枕头,它们有款式,材质,线数和颜色。每组选项对于产品都是唯一的,但我知道在呈现页面之前它们是什么。

谢谢你。

3 个答案:

答案 0 :(得分:1)

构造数据的自然方式是使用多维数组(每个属性的一个维度),其中值为true或false。我用这个想法建模了它,但是使用了关联数组(在JavaScript中也称为对象)。

数据:

var availability = {
  'American Apparel' : {
    'S' : {
      'black' : true,
      'green' : true
    },
    'M' : {
      'black' : true,
      'white' : true
    }
  },
  'Gildan' : {
    'M' : {
      'black' : true
    },
    'XL' : {
      'black' : true,
      'white' : true,
      'green' : true
    }
  }
};

现在您只需要一个函数来在选择某些选项时返回可能的选项。初稿如下,但我确信它可以大大改善。如果设置了属性,则将值传递给函数,否则传递undefined。该函数返回一个具有3个数组的对象,指示用户选择的有效选项。最后的用法示例..

function pushIfNotIn(arr, item) {
  if (arr.indexOf(item) === -1) arr.push(item);
}

function getAvailability(styleValue, sizeValue, colorValue) {
  var av = {
    style : [],
    size : [],
    color : []
  };

  for (var style in availability) {
    if (styleValue === undefined || styleValue === style) {
      for (var size in availability[style]) {
        if (sizeValue === undefined || sizeValue === size) {
          for (var color in availability[style][size]) {
            if (colorValue === undefined || colorValue === color) {
              if (availability[style][size][color]) {
                pushIfNotIn(av.style, style);
                pushIfNotIn(av.size, size);
                pushIfNotIn(av.color, color);
              }
            }
          }
        }
      }
    }
  }
  return av;
}

console.log(getAvailability(undefined, 'M', undefined));
console.log(getAvailability('American Apparel', 'S', undefined));
console.log(getAvailability(undefined, 'M', 'black'));
console.log(getAvailability(undefined, 'M', 'green'));
console.log(getAvailability(undefined, undefined, 'green'));

DEMO:http://jsbin.com/uHAyirOX/1/edit

显然,可以从此方法推断出更通用的解决方案,在可用性对象中具有可变数量的参数和更多级别。不过,你还有一些工作要做。


更新:通用解决方案(以相同方式调用)

function pushIfNotIn(arr, item) {
    if (!arr) arr = [];
    if (arr.indexOf(item) === -1) arr.push(item);
    return arr;
}

function getAvailability() {
  var result = [];  
  ~function getAvailabilityRecursive (level, availability, values) { 
    if (!values.length) return true;
    var isAvailable = false;
    var val = values[0];
    values = values.slice(1);
    for (var key in availability) {  
      if ((val === undefined || val === key) &&
          (getAvailabilityRecursive(level+1, availability[key], values))){
        result[level] = pushIfNotIn(result[level], key);
        isAvailable = true;        
      }
    }    
    return isAvailable;    
  }(0, availability, Array.prototype.slice.call(arguments));

  return result;  
}

DEMO:http://jsbin.com/uHAyirOX/3/edit

答案 1 :(得分:1)

低技术方法,对于任何维护它的人来说都是显而易见的。

这可能是一个简单明了的Ajax响应:

var products = [
    { id: 101, style: 'aa', size: 's', colour: 'grey' },
    { id: 102, style: 'aa', size: 'm', colour: 'grey' },
    { id: 103, style: 'aa', size: 'l', colour: 'black' },
    /* ... 500 more ... */
    { id: 604, style: 'gi', size: 'l', colour: 'blue' }
];

现在只需在客户端过滤该数组暴力:

function Drilldown(items, properties) {
    var self = this,
        numItems = items.length,
        numProps = properties.length;

    self.setFilter = function (filterDef) {
        var i, item, p, prop, pass, filter = filterDef || {};

        self.items = [];
        self.properties = {};

        for (i = 0; i < numItems; i++) {
            item = items[i];
            pass = true;
            for (p = 0; pass && p < numProps; p++) {
                prop = properties[p];
                pass = pass && (!filter[prop] || filter[prop] === item[prop]);
                if (!self.properties.hasOwnProperty(prop)) {
                    self.properties[prop] = {};
                }
                if (!self.properties[prop].hasOwnProperty(item[prop])) {
                    self.properties[prop][item[prop]] = [];
                }
            }
            if (pass) {
                self.items.push(item);
                for (p = 0; p < numProps; p++) {
                    prop = properties[p];
                    self.properties[prop][item[prop]].push(item);
                }
            }
        }
    };
    self.setFilter();
}

用法:

var dd = new Drilldown(products, ['style', 'size', 'colour']);

dd.setFilter({size: 'l'});
/*
dd.items => [ array of size L products ]
dd.properties => {
    style: {
        aa: [ array of size L products in style 'aa' (1) ],
        gi: [ array of size L products in style 'gi' (1) ]
    },
    size: {
        s: [ array of size L products in size S (0) ],
        m: [ array of size L products in size M (0) ],
        l: [ array of size L products in size L (2) ]
    },
    colour: {
        grey:  [ array of size L products in Grey  (0) ],
        black: [ array of size L products in Black (1) ],
        blue:  [ array of size L products in Blue  (1) ]
    }
*/

dd.properties包含所有属性组合。当然,有些条目是空的(数组长度为0),但所有条目都是那里。这使得直接索引到这个对象。

答案 2 :(得分:0)

我想我会做一些事情:

var items = {

            'item1':{

                'level1' : {
                    'level2' : {},
                    'level2' : {'level3' :{}}
                },

                'level1' : {
                    'level2' : {},
                    'level2' : {'level3' :{}}
                }
            },

            'item2':{

                'level1' : {
                    'level2' : {},
                    'level2' : {'level3' :{}}
                },

                'level1' : {
                    'level2' : {},
                    'level2' : {'level3' :{}}
                }

            }
        }

第一个选择器(例如Style)可以指示下一个(Color)的可用性,等等。

在任何级别,用户只能更改以下级别。