Сортировка Div в JQuery по пользовательскому порядку сортировки - PullRequest
15 голосов
/ 22 октября 2009

Я пытаюсь пересортировать дочерние элементы тега input, сравнивая их атрибут категории к порядку категорий в Javascript переменная category_sort_order. Затем мне нужно удалить div, чей атрибут категории не отображается в category_sort_order.

Ожидаемый результат должен быть:

любой
product1
product2
скачать

код:

<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 голосов
/ 22 октября 2009

Я написал плагин 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. Кроме того, если использовать это для ряда элементов, это можно улучшить, добавляя все элементы в массиве за один раз вместо итерации по массиву и добавляя по одному за раз. Это, вероятно, было бы хорошим примером для DocumentFragments .

15 голосов
/ 25 октября 2009

Просто обратите внимание,

Поскольку существует 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
}

Это отсортирует все div, которые являются потомками элемента с id = "input".

9 голосов
/ 22 октября 2009

Вот как это сделать. Я использовал этот 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 входного элемента, содержащих атрибут категории. Затем он сохраняет их HTML-контент и свою категорию в двух отдельных массивах (но в одном месте.

Затем он очищает все div'ы под входным div.

Наконец, он просматривает ваши категории в порядке, указанном в массиве, и добавляет соответствующие дочерние элементы div в правильном порядке.

Секция For loop

@ eyelidlessness хорошо объясняет циклы, но я тоже попробую. в контексте этого кода.

Первая строка:

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

Означает, что следующий код (все в фигурных скобках {code}) будет повторяться несколько раз. Хотя формат выглядит архаичным (и как-то так), он говорит:

  1. Создайте числовую переменную с именем i и установите ее равной нулю
  2. Если эта переменная меньше, чем количество элементов в массиве category_sort_order, то делать то, что в скобках
  3. Когда скобки заканчиваются, добавьте один к переменной i (i ++ означает добавить один)
  4. Затем он повторяет шаги два и три, пока, наконец, я не станет больше, чем количество категорий в этом массиве.

A.K.A Все, что в скобках, будет выполнено один раз для каждой категории.

Двигаясь дальше ... для каждой категории вызывается еще один цикл. Вот этот:

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

перебирает все категории div, которые мы только что удалили с экрана.

В этом цикле оператор if проверяет, соответствует ли какой-либо элемент div с экрана текущей категории. Если это так, они добавляются, если нет, цикл продолжает поиск до тех пор, пока не пройдет через каждый div.

5 голосов
/ 22 октября 2009

Добавление (или добавление) узлов 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.
1 голос
/ 22 октября 2009

Я подумал, что это действительно интересная проблема, вот простое, но не невероятно эффективное решение для сортировки, которое я придумал.

Вы можете просмотреть тестовую страницу на 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 может и не быть необходимым, но он просто безопаснее. Ваш звонок.

Возможно, вы могли бы очистить некоторую производительность, сохранив ссылку на родителя и просто получая потомков каждый раз вместо повторного запуска селектора. Я собирался для простоты все же. Вы должны вызывать селектор каждый раз, потому что порядок меняется в некотором роде, и я нигде не храню ссылку на родителя.

0 голосов
/ 22 октября 2009

Кажется, довольно прямо использовать метод 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' );

Если вы используете старую версию jQuery (1.2), в которой нет метода sort, вы можете добавить ее с помощью:

jQuery.fn.sort = Array.prototype.sort;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...