【问题标题】:What is the most efficient way to sort an Html Select's Options by value, while preserving the currently selected item?按值对 Html Select 的选项进行排序的最有效方法是什么,同时保留当前选定的项目?
【发布时间】:2010-09-07 22:27:17
【问题描述】:

我有 jQuery,但我不确定它是否有任何内置的排序助手。我可以为每个项目的textvalueselected 属性制作一个二维数组,但我认为Array.sort() 内置的javascript 不能正常工作。

【问题讨论】:

  • 自我注意(因为我已经通过谷歌多次回到这个问题):这是你写的一个很好的解决方案:gist.github.com/1072537

标签: javascript jquery arrays sorting html-select


【解决方案1】:

将选项提取到临时数组中,排序,然后重建列表:

var my_options = $("#my_select option");
var selected = $("#my_select").val();

my_options.sort(function(a,b) {
    if (a.text > b.text) return 1;
    if (a.text < b.text) return -1;
    return 0
})

$("#my_select").empty().append( my_options );
$("#my_select").val(selected);

Mozilla's sort documentation(特别是 compareFunction)和Wikipedia's Sorting Algorithm page 是相关的。

如果您想让排序不区分大小写,请将text 替换为text.toLowerCase()

上面显示的排序函数说明了如何排序。准确排序非英语语言可能很复杂(请参阅unicode collation algorithm)。在 sort 函数中使用localeCompare 是一个很好的解决方案,例如:

my_options.sort(function(a,b) {
    return a.text.localeCompare(b.text);
});

【讨论】:

  • 3 年后重新审视这个问题,这条路线似乎是正确的方法
  • 请注意,这是区分大小写的——也就是说,它会将所有以大写字母开头的事物排在以小写字母开头的事物之前。如果不希望这样做,只需在每个 .text 之后添加一个 .toUpperCase()
  • 此外,它不会按原样保留所有浏览器中当前选择的选项(Chrome 会记住选择的内容,但 firefox 和 ie 没有,并且在读取选项后选择了最后一个元素)。要解决此问题,请在排序前保存当前选定的值,然后重新选择它。即,在其他任何事情之前执行var selected = $("#my_select").val();,然后在附加排序选项之后,恢复val,即$("#my_select").val(selected);
  • 酷。 'else' 字样可以去掉。无论如何返回结束函数。
  • @TJEllis 关于区分大小写,这个问题提供了更多信息,为什么在忽略大小写时应该使用.toUpperCase().toLowerCase() stackoverflow.com/questions/2140627/…
【解决方案2】:

稍微修改了上面汤姆的回答,使其实际上修改了要排序的选择框的内容,而不仅仅是返回排序后的元素。

$('#your_select_box').sort_select_box();

jQuery 函数:

$.fn.sort_select_box = function(){
    // Get options from select box
    var my_options = $("#" + this.attr('id') + ' option');
    // sort alphabetically
    my_options.sort(function(a,b) {
        if (a.text > b.text) return 1;
        else if (a.text < b.text) return -1;
        else return 0
    })
   //replace with sorted my_options;
   $(this).empty().append( my_options );

   // clearing any selections
   $("#"+this.attr('id')+" option").attr('selected', false);
}

【讨论】:

  • 这个答案接近顶部,但没有正确选择
【解决方案3】:

我刚刚将 Mark 的想法封装在一个 jquery 函数中

$('#your_select_box').sort_select_box();

jQuery函数:

$.fn.sort_select_box = function(){
    var my_options = $("#" + this.attr('id') + ' option');
    my_options.sort(function(a,b) {
        if (a.text > b.text) return 1;
        else if (a.text < b.text) return -1;
        else return 0
    })
   return my_options;
}

【讨论】:

  • 如何将它添加到我当前的点击事件中? $('#addwire').click(function() { return !$('#wireselection option:selected').remove().appendTo('#wires').sort_select_box(); });似乎不起作用
【解决方案4】:

我在对@Juan Perez 的评论中提到的解决方案

$.fn.sortOptions = function(){
    $(this).each(function(){
        var op = $(this).children("option");
        op.sort(function(a, b) {
            return a.text > b.text ? 1 : -1;
        })
        return $(this).empty().append(op);
    });
}

用法:

$("select").sortOptions();

这仍然可以改进,但我不需要添加更多的花里胡哨:)

【讨论】:

    【解决方案5】:

    嗯,在 IE6 中,它似乎对嵌套数组的 [0] 项进行排序:

    function sortSelect(selectToSort) {
        var arrOptions = [];
    
        for (var i = 0; i < selectToSort.options.length; i++)  {
            arrOptions[i] = [];
            arrOptions[i][0] = selectToSort.options[i].value;
            arrOptions[i][1] = selectToSort.options[i].text;
            arrOptions[i][2] = selectToSort.options[i].selected;
        }
    
        arrOptions.sort();
    
        for (var i = 0; i < selectToSort.options.length; i++)  {
            selectToSort.options[i].value = arrOptions[i][0];
            selectToSort.options[i].text = arrOptions[i][1];
            selectToSort.options[i].selected = arrOptions[i][2];
        }
    }
    

    我会看看这是否适用于其他浏览器...

    编辑:它也适用于 Firefox,哇哦!

    还有比这更简单的方法吗? javascript 或 jQuery 中是否有一些方法可以对我缺少的选择进行排序,或者这是最好的方法?

    【讨论】:

    • 注意这个函数不对option元素进行排序;它会更改现有元素上的 [value,text,selected] 以便对它们进行排序(在这种情况下按值)。这对于大多数应用程序来说已经足够了,但是如果您有其他属性(CSS、工具提示等),那么这种方法就不够了。
    【解决方案6】:

    a closed jQuery ticket 表示应该可以工作,但未包含在核心中。

    jQuery.fn.sort = function() {
      return this.pushStack( [].sort.apply( this, arguments ), []);
    };
    

    引用自a Google Groups thread,我想你只是传入一个用于排序的函数,像这样

    function sortSelect(selectToSort) {
        jQuery(selectToSort.options).sort(function(a,b){ 
            return a.value > b.value ? 1 : -1; 
        });
    }
    

    希望对你有帮助!

    【讨论】:

    • sortSelect 函数的一些问题:这不考虑相等的选项。根据值而不是文本排序。 jQuery 对象没有名为“选项”的属性。没有任何效果,因为您必须将选项附加到新的选择元素。
    【解决方案7】:

    这是一个更好的解决方案。 向 JQuery 声明一个全局函数

    $.fn.sortSelect = function() {
        var op = this.children("option");
        op.sort(function(a, b) {
            return a.text > b.text ? 1 : -1;
        })
        return this.empty().append(op);
    }
    

    并从代码中调用函数。

    $("#my_select").sortSelect();
    

    【讨论】:

    • 我对此使用了一种变体,将内部部分包裹在 $(this).each() 中,这样我就可以传递一个选择器来一次处理多个。
    • 另外,您需要使用$(this) 而不仅仅是this
    【解决方案8】:

    Array.sort() 默认将每个元素转换为字符串,然后比较这些值。所以["value", "text", "selected"] 被排序为"value, text, selected"。在大多数情况下,这可能会正常工作。

    如果您确实想单独对值进行排序,或者将值解释为数字,则可以将比较函数传递给 sort():

    arrOptions.sort(function(a,b) { return new Number(a[0]) - new Number(b[0]); });
    

    【讨论】:

      【解决方案9】:

      记住:如果你想使用上下文选择器,仅仅连接 ID 是行不通的

      $.fn.sort_select_box = function(){
          var my_options = $("option", $(this));
          my_options.sort(function(a,b) {
              if (a.text > b.text) return 1;
              else if (a.text < b.text) return -1;
              else return 0
          });
          $(this).empty().append(my_options);
      }
      
      // Usando:
      $("select#ProdutoFornecedorId", $($context)).sort_select_box();
      

      【讨论】:

        【解决方案10】:

        有点晚了,但我已经实现了一个更复杂的函数,你可以将其包含在内。它有一些用于不同输出的选项。它还可以根据标签递归到&lt;OPTGROUP&gt;标签。

        $.fn.sortSelect = function(options){
        
            const OPTIONS_DEFAULT = {
                recursive:      true,   // Recurse into <optgroup>
                reverse:        false,  // Reverse order
                useValues:      false,  // Use values instead of text for <option> (<optgruop> is always label based)
                blankFirst:     true,   // Force placeholder <option> with empty value first, ignores reverse
            }
        
            if (typeof options != "object" || null === options) {
                options = OPTIONS_DEFAULT;
            }
        
            var sortOptions = function($root, $node, options){
        
                if ($node.length != 1) {
                    return false;
                }
        
                if ($node[0].tagName != "SELECT" && $node[0].tagName != "OPTGROUP") {
                    return false;
                }
        
                if (options.recursive) {
                    $node.children('optgroup').each(function(k, v){
                        return sortOptions($root, $(v), options);
                    });
                }
        
                var $options        = $node.children('option, optgroup');
                var $optionsSorted  = $options.sort(function(a, b){
        
                    if (options.blankFirst) {
                        if (a.tagName == "OPTION" && a.value == "") {
                            return -1;
                        }
        
                        if (b.tagName == "OPTION" && b.value == "") {
                            return 1;
                        }
                    }
        
                    var textA = (a.tagName == "OPTION" ? (options.useValues ? a.value : a.text) : a.label);
                    var textB = (b.tagName == "OPTION" ? (options.useValues ? a.value : b.text) : b.label);
        
                    if (textA > textB) {
                        return options.reverse ? -1 : 1;
                    }
        
                    if (textA < textB) {
                        return options.reverse ? 1 : -1;
                    }
        
                    return 0;
        
                });
        
                $options.remove();
                $optionsSorted.appendTo($node);
        
                return true;
        
            };
        
            var selected = $(this).val();
            var sorted = sortOptions($(this), $(this), {...OPTIONS_DEFAULT, ...options});
            $(this).val(selected);
        
            return sorted;
        
        };
        

        然后,您可以在任何 &lt;SELECT&gt; 标记上调用 sortSelect() 函数,或者仅调用单个 &lt;OPTGROUP&gt; 来仅对组的选项进行排序。

        例子:

        $('select').sortSelect();
        

        使用“reverse”选项反转顺序:

        $('select').sortSelect({
            reverse: true
        });
        

        您可以自动将此应用于所有选择,也许只有当它们包含一个重要的类(例如“js-sort”)时:

        $('select.js-sort').each(function(k, v){
            $(v).sortSelect();
        });
        

        【讨论】:

          【解决方案11】:

          似乎 jquery 对于 html 选择元素中的排序选项仍然不是特别有用。 下面是一些用于排序选项的普通 javascript 代码:

          function sortOptionsByText(a,b) {
            // I keep an empty value option on top, b.value comparison to 0 might not be necessary if empty value is always on top...
            if (a.value.length==0 || (b.value.length>0 && a.text <= b.text)) return -1; // no sort: a, b
            return 1; // sort switches places: b, a
          }
          function sortOptionsByValue(a,b) {
            if (a.value <= b.value) return -1; // a, b
            return 1; // b, a
          }
          function clearChildren(elem) {
            if (elem) {
              while (elem.firstChild) {
                elem.removeChild(elem.firstChild);
              }
            }
          }
          function sortSelectElem(sel,byText) {
            const val=sel.value;
            const tmp=[...sel.options];
            tmp.sort(byText?sortOptionsByText:sortOptionsByValue);
            clearChildren(sel);
            sel.append(...tmp);
            sel.value=val;
          }
          RACE: <select id="list" size="6">
            <option value="">--PICK ONE--</option>
            <option value="1">HUMANOID</option>
            <option value="2">AMPHIBIAN</option>
            <option value="3">REPTILE</option>
            <option value="4">INSECTOID</option>
          </select><br>
          <button type="button" onclick="sortSelectElem(document.getElementById('list'));">SORT LIST BY VALUE</button><br>
          <button type="button" onclick="sortSelectElem(document.getElementById('list'),true);">SORT LIST BY TEXT</button>

          【讨论】:

            【解决方案12】:

            使用 jquery,这在 Chrome 中对我有用,以便对由数据库未排序元素组成的选择进行排序。

            $(document).ready(function(){
                
                var $list = $("#my_select");
                var selected = $("#my_select").val(); //save selected value
                
                $list.children().detach().sort(function(a, b) {
                    return $(a).text().localeCompare($(b).text());
                  }).appendTo($list);  //do the sorting locale for latin chars
                
                $("#my_select").val(selected); //select previous selected value
            
            });
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-11-07
              • 2011-12-04
              • 2010-11-05
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多