我正在使用的电子商务平台缺乏重新排序产品属性字段选项的功能。它真的很糟糕,因为要插入一个新选项,你几乎必须删除所有现有选项并重新开始。我试图做客户端而不是。这就是我正在使用的(这是鞋子尺码):
这些实际上是表单中某些<option>
的文本。值的格式为X Y Z
,其中:
X
是一个整数Y
是字符串“1/2”,可能不存在Z
是一个字母代码,可以是“D”,“E”,“EEE”或“EEEE”,也可能不存在以上所需的顺序是:
我已经学习了一些关于javascript sort()
函数的知识,但是还没有完全理解你可以传递给它的比较函数是如何工作的。到目前为止我已经有了这个:
<select>
<option>9 EE</option>
<option>9 1/2 EE</option>
<option>10 EE</option>
<option>10 1/2 EE</option>
<option>11 EE</option>
<option>11 1/2 EE</option>
<option>9 EEEE</option>
<option>9 1/2 D</option>
<option>9 1/2 EEEE</option>
<option>10 EEEE</option>
<option>10 1/2 EEEE</option>
<option>11 EEEE</option>
<option>9 D</option>
<option>11 1/2 EEEE</option>
</select>
我从这个答案的代码开始:https://stackoverflow.com/a/667198/398242
$("select").html($("option").sort(function (a, b) {
return a.text == b.text ? 0 : a.text < b.text ? -1 : 1
}));
对这样的项目进行排序(即使是第一个标准也不起作用):
我在javascript '11' > '9'
中看到false
返回function compare(a, b) {
if (a is less than b by some ordering criterion)
return -1;
if (a is greater than b by the ordering criterion)
return 1;
// a must be equal to b
return 0;
}
,这对我来说毫无意义。
MDN describes the compare function argument就这样,我得到了它:
{{1}}
...但我不知道如何调整它以符合我的要求。我尝试了一些东西,但我觉得我在黑暗中拍摄。我试图表明我花了一些时间来尝试理解这个问题。我有兴趣了解更多,但是现在我只想解决这个问题。
答案 0 :(得分:2)
按照您希望的顺序将值放在数组中:
var shoeSizes = [ '9 D','9 1/2 D','9 EE','9 1/2 EE', ...]
使用 Array.protoype.indexOf (with a shim for older browsers)获取数组中匹配文本的索引。使用索引进行比较,例如:
function(a,b) {
return shoeSizes.indexOf(a) - shoeSizes.indexOf(b);
}
如果您需要处理数组中没有的值,请测试 indexOf 返回的值,如果它是-1,则替换默认值。
或者,您可以将大小设置为对象中属性值的名称,并指定特定值:
var shoeSizes = { '9 D': 5, '9 1/2 D': 10, '9 EE': 15, '9 1/2 EE': 20, ...};
然后使用比较中的值:
function(a,b) {
return shoeSizes[a] - shoeSizes[b];
}
或者允许默认值:
function(a,b) {
return (a in shoeSizes? shoeSizes[a] : 1000) - (b in shoeSizes? shoeSizes[b] : 1000);
}
答案 1 :(得分:2)
由于您已经格式化了文本,因此一种方法是在比较它们之前规范化文本元素。
这个解决方案可能不是那么理想,但会完成工作
$("select").html($("option").sort(function (a, b) {
return nomalize(a.text) < nomalize(b.text) ? -1 : 1;
}));
function nomalize(val){
var parts = val.split(' '), op = '';
op = parts[0].length == 1 ? '0' + parts[0] : parts[0];
if(parts.length > 1){
if(/[a-z]/i.test(parts[1])){
op += '0/0' + parts[1];
} else {
op += parts[1]
}
}
op += parts.length > 2 ? parts[2] : '';
return op;
}
演示:Fiddle
如果有人可以建议任何解决方案来进一步优化它
答案 2 :(得分:1)
首先要了解的是,12
确实 小于9
如果您要对文本项目进行排序,而不是数字。这是因为<1>
<2>
小于<9>
<nothing>
,因为在这种情况下1
和9
是“主键”。
您面临的第二个问题是长度(9 1/2)是主键还是宽度(EE)。我怀疑前者会更有意义,所以继续这样做。
决定之后,最好的办法是为调用提供一个排序函数,将每个字符串转换为数值,然后比较该值。例如:
1/2
,请将0.5
添加到该值。0.5
的值并添加(例如a
- > 0.01,B
- &gt ; 0.02,...,EEEE
- &gt; 0.08等等。)最后一个取决于宽度的相对排序,我选择了一个典型的美国系统。
你最终得到的是一个值,它决定了正确的排序,你的排序功能可以简单地进行数值比较。一个例子如下:
function xlat(s) {
var s2 = s.split(" ");
var n = parseInt(s2[0]);
if (s2.length == 1) { return n; }
var last = s2[1];
if (last == '1/2') {
n = n + 0.5;
if (s2.length == 2) { return n; }
last = s2[2];
}
var widths = ['A','B','C','D','E','EE','EEE','EEEE','F','G'];
n = n + widths.indexOf(last) / 100;
return n;
}
$("select").html($("option").sort(function (a, b) {
var na = xlat(a.text);
var nb = xlat(b.text);
return na == nb ? 0 : na < nb ? -1 : 1;
}));
xlat
函数在这里很重要。它首先将大小拆分为1个,2个或3个元素的数组,并获取第一个的数值。如果第二个和第三个不存在,则返回此值(处理“裸”大小,如9
或13
)。
否则它决定它是否是半增量长度 - 如果第二个字段是1/2
则决定。此时,它还会检测是否没有宽度并返回大小。
一旦超过这一点,我们就有了大小(整数或一半),last
变量保持宽度。然后,我们只需根据此大小在数组中的位置添加一个值,进行适当修改(除以100),这样就不会影响主键。
通过使用您自己的代码,您可以得到(正如预期的那样):
9 D
9 EE
9 EEEE
9 1/2 D
9 1/2 EE
9 1/2 EEEE
10 EE
10 EEEE
10 1/2 EE
10 1/2 EEEE
11 EE
11 EEEE
11 1/2 EE
11 1/2 EEEE
答案 3 :(得分:1)
首先需要定义一个合适的排序键,您可以使用它进行合理的比较;以下函数使用正则表达式来挖掘有用的信息位:
function sortkey(val)
{
var matches = val.match(/^(\d+)( 1\/2)? (\w+)$/),
number = +matches[1];
if (matches[2]) {
number += 0.5; // add "1/2"
}
return [number, matches[3]];
}
第一场比赛被投入一个数字;如果第二个匹配可用,则添加0.5
。然后,将最后一个匹配作为辅助排序键添加。返回值是这样的:
[9.5, 'EE']
然后,此结构可用于比较功能:
function compareFunc(a, b) {
var sa = sortkey(a.text),
sb = sortkey(b.text);
if (sa[0] == sb[0]) {
return sa[1] < sb[1] ? -1 : 1;
} else {
return sa[0] < sb[0] ? -1 : 1;
}
}
应用于您的特定代码:
var $sorted = $('select > option').sort(compareFunc);
$('select').html($sorted);
答案 4 :(得分:1)
检查一下:
$("select").html($("option").sort(function (a, b) {
var regex = /(\d+)((?: 1\/2)? )([DE]+)/;
var abreakdown = a.text.match(regex), bbreakdown = b.text.match(regex);
if (parseInt(abreakdown[1]) === parseInt(bbreakdown[1])) {
if (abreakdown[3] === bbreakdown[3]) {
return (abreakdown[2] === bbreakdown[2] ? 0 : (abreakdown[2] < bbreakdown[2] ? -1 : 1));
} else {
return abreakdown[3] < bbreakdown[3] ? -1 : 1;
}
} else { return parseInt(abreakdown[1]) - parseInt(bbreakdown[1]); }
}));
它使用正则表达式来分解碎片,然后根据每个组件进行比较。
答案 5 :(得分:1)
我看到你已经有了一个有效的解决方案,但仅仅是为了比较(双关语),这是其他许多方法之一(fiddle):
// Make a shoe size sortable as text
function sortableSize( text ) {
// Split the size into parts separated by spaces
var parts = text.split( ' ' );
// The first part is the size number;
// make sure it is two digits (09,10,etc.)
if( parts[0].length == 1 )
parts[0] = '0' + parts[0];
// If it wasn't a 1/2 size, make it 0/2
if( parts.length == 2 )
parts.splice( 1, 0, '0/2' );
// So '9 EE' becomes '09 0/2 EE'
return parts.join( ' ' );
}
var $options = $('#sizes option');
$options = $options.sort( function( a, b ) {
a = sortableSize( a.text );
b = sortableSize( b.text );
return a < b ? -1 : a > b ? 1 : 0;
});
$('#sizes').html( $options );
此方法创建每个鞋码的文本表示,可直接排序为文本。然后它使用那些文本表示进行排序。