按自定义排序顺序对jQuery中的Div进行排序

时间:2009-10-21 21:03:06

标签: javascript jquery sorting

我正在尝试通过比较对标记input的子元素进行重新排序 他们的类别属性为Javascript中的类别顺序 变量category_sort_order。然后我需要删除其category属性的div 没有出现在category_sort_order

预期结果应为:

  

任何
  产品1
  产品2
  下载

代码:

<div id="input">
<div category="download">download</div>
<div category="video">video1</div>
<div category="video">video2</div>
<div category="product">product1</div>
<div category="any">any</div>
<div category="product">product2</div>
</div>

<script type="text/javascript">
var category_sort_order = ['any', 'product', 'download'];
</script>

我甚至不知道从哪里开始这项任务,但如果你能提供任何帮助,我将非常感激。

6 个答案:

答案 0 :(得分:17)

我写了一个jQuery插件来做这种事情,可以很容易地适应你的用例。

The original plugin is here

这是对你提问的改进

(function($) {

$.fn.reOrder = function(array) {
  return this.each(function() {

    if (array) {    
      for(var i=0; i < array.length; i++) 
        array[i] = $('div[category="' + array[i] + '"]');

      $(this).empty();  

      for(var i=0; i < array.length; i++)
        $(this).append(array[i]);      
    }
  });    
}
})(jQuery);

并使用如此

var category_sort_order = ['any', 'product', 'download'];
$('#input').reOrder(category_sort_order);

这次碰巧是为了获得产品的正确顺序,因为product1出现在原始列表中的product2之前,但是在放入数组并附加到DOM之前,它可以很容易地更改为排序类别。此外,如果将它用于许多元素,可以通过一次性附加数组中的所有元素而不是迭代数组并一次附加一个元素来改进它。这可能是DocumentFragments的好例子。

答案 1 :(得分:15)

请注意,

由于有jQuery 1.3.2排序很简单,没有任何插件,如:

$('#input div').sort(CustomSort).appendTo('#input');
function CustomSort( a ,b ){
     //your custom sort function returning -1 or 1
     //where a , b are $('#input div') elements
}

这将对所有具有id =“input”的元素的子元素进行排序。

答案 2 :(得分:9)

以下是如何做到这一点。我使用此SO question作为参考。

我测试了这段代码,它适用于您的示例:

$(document).ready(function() {
    var categories = new Array();
    var content = new Array();
    //Get Divs
    $('#input > [category]').each(function(i) {
        //Add to local array
        categories[i] = $(this).attr('category');
        content[i] = $(this).html();
    });

    $('#input').empty();

    //Sort Divs
    var category_sort_order = ['any', 'product', 'download'];
    for(i = 0; i < category_sort_order.length; i++) {
        //Grab all divs in this category and add them back to the form
        for(j = 0; j < categories.length; j++) {
            if(categories[j] == category_sort_order[i]) {
                $('#input').append('<div category="' + 
                           category_sort_order[i] + '">' 
                           + content[j] + '</div>');
            }
        };
    }
});

工作原理

首先,此代码需要JQuery库。如果您目前没有使用它,我强烈推荐它。

代码首先获取包含category属性的输入div的所有子div。然后它将他们的html内容及其类别保存到两个单独的数组(但在同一位置。

接下来它会清除输入div下的所有div。

最后,它按照您在数组中指定的顺序浏览您的类别,并以正确的顺序附加匹配的子div。

For循环部分

@eyelidlessness在解释循环方面做得很好,但我也会对它进行解释。在此代码的上下文中。

第一行:

for(i = 0; i < category_sort_order.length; i++) {

表示后面的代码(大括号{code}中的所有内容)将重复多次。虽然格式看起来过时(而且排序是),但它说:

  1. 创建一个名为i的数字变量并将其设置为零
  2. 如果该变量小于category_sort_order数组中的项目数,那么在括号中做什么
  3. 当括号完成时,将一个添加到变量i(i ++表示添加一个)
  4. 然后重复第二步和第三步,直到我最终大于该数组中的类别数。
  5. A.K.A括号中的任何内容都将针对每个类别运行一次。

    继续...对于每个类别,调用另一个循环。这一个:

    for(j = 0; j < categories.length; j++) {
    

    遍历我们刚刚从屏幕上删除的div的所有类别。

    在此循环中,if语句检查屏幕中的任何div是否与当前类别匹配。如果是这样,它们会附加,如果不是,循环继续搜索,直到它遍历每个div。

答案 3 :(得分:5)

再次追加(或预先添加)DOM节点实际上会按照您想要的顺序对它们进行排序。

使用jQuery,您只需按照您想要的顺序选择它们,然后再将它们附加(或预先添加)到它们的容器中。

$(['any', 'product', 'video'])
    .map(function(index, category)
    { 
         return $('[category='+category+']');
    })
    .prependTo('#input');

抱歉,您错过了想要删除不属于您的类别列表的节点。这是更正后的版本:

// Create a jQuery from our array of category names, 
// it won't be usable in the DOM but still some 
// jQuery methods can be used
var divs = $(['any', 'product', 'video'])
// Replace each category name in our array by the
// actual DOM nodes selected using the attribute selector
// syntax of jQuery.
    .map(function(index, category)
    { 
        // Here we need to do .get() to return an array of DOM nodes
        return $('[category='+category+']').get();
    });
// Remove everything in #input and replace them by our DOM nodes.
$('#input').empty().append(divs);

// The trick here is that DOM nodes are selected 
// in the order we want them in the end.
// So when we append them again to the document,
// they will be appended in the order we want.

答案 4 :(得分:1)

我认为这是一个非常有趣的问题,这是一个简单但不太令人难以置信的高性能排序解决方案。

您可以在jsbin上查看测试页面:http://jsbin.com/ocuta

function compare(x, y, context){
  if($.inArray(x, context) > $.inArray(y, context)) return 1; 
}
function dom_sort(selector, order_list) {
 $items = $(selector);
 var dirty = false;
 for(var i = 0; i < ($items.length - 1); i++) {
  if (compare($items.eq(i).attr('category'), $items.eq(i+1).attr('category'), order_list)) {
   dirty = true;
   $items.eq(i).before($items.eq(i+1).remove());
  }
 }
 if (dirty) setTimeout(function(){ dom_sort(selector, order_list); }, 0); 
};
dom_sort('#input div[category]', category_sort_order);

请注意,setTimeout可能没有必要,但它感觉更安全。你的电话。

您可以通过存储对父级的引用并且每次只获取子级而不是重新运行选择器来清理某些性能。我的目的是为了简单。你必须每次都调用选择器,因为顺序会改变排序,而且我不会在任何地方存储对父级的引用。

答案 5 :(得分:0)

对于这个方法使用sort方法似乎相当直接:

var category_sort_order = ['any', 'product', 'download'];

// select your categories
$('#input > div')

  // filter the selection down to wanted items
  .filter(function(){
    // get the categories index in the sort order list ("weight")
    var w = $.inArray( $(this).attr('category'), category_sort_order );
    // in the sort order list?
    if ( w > -1 ) {
      // this item should be sorted, we'll store it's sorting index, and keep it
      $( this ).data( 'sortindex', w );
      return true;
    }
    else {
      // remove the item from the DOM and the selection
      $( this ).remove();
      return false;
    }
  })

  // sort the remainder of the items
  .sort(function(a, b){
    // use the previously defined values to compare who goes first
    return $( a ).data( 'sortindex' ) - 
           $( b ).data( 'sortindex' );
  })

  // reappend the selection into it's parent node to "apply" it
  .appendTo( '#input' );

如果您碰巧使用的是没有sort方法的旧版jQuery(1.2),可以使用以下方法添加:

jQuery.fn.sort = Array.prototype.sort;