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

Javascript array/object/hash table to track cart availability

本文关键字:数组 对象 哈希表 Javascript 跟踪 购物车 可用性 用于      更新时间:2023-09-26

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

样式:

  • 美国服装
  • 吉尔丹

尺寸:

  • S
  • M
  • L
  • XL

颜色:

  • 蓝色
  • 黑色
  • 白色
  • 灰色

并不是每种款式都有各种尺寸和颜色的组合,但除了购物车在页面上的布局之外,用户没有固定的方式可以先选择款式,然后选择尺寸而不强制选择,这将成为销售的障碍。

现在,当用户从任何下拉框中选择任何内容时,都会对服务器进行ajax调用,以计算其他下拉框应包含的内容,例如,如果用户首先选择Size(L),则颜色可能会变为蓝色和黑色,因为白色和灰色在Large中不可用,但更糟糕的是,白色可能可用,但仅在Gildan样式中可用。

无论如何,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>

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

非常感谢。

构建数据的自然方法是使用多维数组(每个属性一个维度),其中的值为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'));

演示:http://jsbin.com/uHAyirOX/1/edit

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


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

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

演示:http://jsbin.com/uHAyirOX/3/edit

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

这可能是一个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),但所有条目都将存在。这使得对该对象进行索引变得简单。

我想我会做一些事情:

var items = {
            'item1':{
                'level1' : {
                    'level2' : {},
                    'level2' : {'level3' :{}}
                },
                'level1' : {
                    'level2' : {},
                    'level2' : {'level3' :{}}
                }
            },
            'item2':{
                'level1' : {
                    'level2' : {},
                    'level2' : {'level3' :{}}
                },
                'level1' : {
                    'level2' : {},
                    'level2' : {'level3' :{}}
                }
            }
        }

第一个选择器(例如样式)可以指定下一个(颜色)的可用性,依此类推

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