用自定义排序方式在jQuery中排序Divs

16

我正在尝试通过比较input标签的子元素的类别属性与Javascript变量category_sort_order中的类别顺序来重新排序它们。然后,我需要删除其类别属性不出现在category_sort_order中的

元素。

期望的结果应该是:

any
product1
product2
download

代码如下:

<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个回答

17

我写了一个jQuery插件,可以轻松地进行适应以实现此类操作。

原始插件在这里

这是对你问题的改进。

(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之前先对类别进行排序。此外,如果将其用于多个元素,则可以通过一次性将数组中的所有元素附加到DOM而不是迭代数组并逐个附加来改进它。 这可能是使用DocumentFragments的好例子


17

请注意,自从有了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"元素的所有子div进行排序。


9
这是如何做到的。我使用这个SO问题作为参考。
我测试了这个代码,对于你的示例它运行良好。
$(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库。如果您目前没有使用它,我强烈建议您使用。

代码开始通过获取包含类别属性的输入div的所有子div来运行。然后将它们的HTML内容和它们的类别保存到两个单独的数组中(但在同一位置)。

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

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

For循环部分

@eyelidlessness很好地解释了for循环,但是我也会在这段代码的上下文中尝试解释它。

第一行:

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

意味着接下来的代码(花括号中的所有内容)将被重复执行许多次。尽管格式看起来有点古老(并且确实是这样),但它表示:
  1. 创建一个名为i的数字变量,并将其设置为零
  2. 如果该变量小于category_sort_order数组中的项目数,则执行花括号中的内容
  3. 当花括号完成后,将变量i加1(i ++表示加1)
  4. 然后它重复步骤二和三,直到i最终大于该数组中的分类数。
即每个类别中花括号内的内容都将运行一次。
接下来...对于每个类别,调用了另一个循环。 这个循环:
for(j = 0; j < categories.length; j++) {

循环遍历我们刚从屏幕中删除的所有div类别。 在此循环中,if语句检查屏幕上是否有任何div与当前类别匹配。 如果是,则将它们添加,如果不是则继续搜索直到遍历完每个div。

感谢您的帮助。我是一个 JavaScript 新手,虽然我理解您代码的第一部分,但是我对第二部分感到困惑。i=0 和 j=0 这两行代码是用来干什么的呢?我经常看到这种写法,但无法理解。再次感谢。 - lightyrs
hnovic,这些是迭代器变量。它们对应于它们迭代的Array的数字键。一个for循环(通常)以其第一条语句作为初始键,第二条语句作为最终键,并以最终语句指示从初始键移动到最终键(通常为i++i--)。 - eyelidlessness
这样做的好处是不会过度操作DOM,但它确实使用了内联HTML,有点让人不舒服,特别是当事情开始变化时。 - Alex Sexton
非常感谢。您在解释这个问题上做得非常好。 - lightyrs

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.

感谢您的帮助。这是如何工作的?您能解释一下吗?再次感谢。 - lightyrs
很好地运用了 map()。数组中的最后一项应该是 download,哈哈 :) - Russ Cam
我喜欢它。这是一个非常优雅的解决方案。 - Borgar

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 可能并不必要,但是这样做会更安全。由您决定。
如果您存储父级引用并每次获取子元素,而不是重新运行选择器,那么可以通过清理一些性能来优化代码。我之前为了简单起见没有这样做。您需要每次调用选择器,因为在排序过程中顺序会发生变化,而我没有将父级引用存储在任何地方。

这也会将在排序顺序数组中找不到的类别放在列表的前面。如果你想把它们放在最后,可以在$.inArray函数中检查-1。 - Alex Sexton

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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接