2009-10-21 19 views
14

Estoy intentando volver a ordenar los elementos secundarios de la etiqueta input mediante la comparación de su categoría atributo a la categoría de orden en la variable Javascript category_sort_order. Entonces necesito eliminar los divs cuyo atributo de categoría no aparece en category_sort_order.Clasificación Divs en jQuery por orden personalizado

El resultado esperado debería ser:

cualquier
product1
producto2
descarga

El código:

<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> 

la verdad es que ni siquiera sabe dónde para comenzar con t su tarea, pero si pudiera proporcionar cualquier tipo de ayuda, estaría extremadamente agradecido.

Respuesta

17

escribí un plugin jQuery para hacer este tipo de cosas que se pueden adaptar fácilmente para su caso de uso.

The original plugin is here

Aquí es una renovación para usted pregunta

(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); 

y utilizar como tal

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

Esto sucede para obtener el orden correcto de los productos esta vez como product1 aparece antes producto2 en la lista original, pero podría cambiarse fácilmente para ordenar las categorías primero antes de ponerlas en el arreglo y agregarlas al DOM. Además, si usa esto para una cantidad de elementos, podría mejorarse al agregar todos los elementos en la matriz de una vez, en lugar de iterar sobre la matriz y anexar uno a la vez. Esto probablemente sería un buen caso para DocumentFragments.

+1

Esto es realmente elegante Russ. Buen trabajo. –

9

Aquí se muestra cómo hacerlo. Utilicé este SO question como referencia.

He probado el código y funciona correctamente para su ejemplo:

$(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>'); 
      } 
     }; 
    } 
}); 

Cómo funciona

En primer lugar, este código requiere la biblioteca jQuery. Si no lo está usando actualmente, lo recomiendo encarecidamente.

El código comienza por obtener todos los divs secundarios del div de entrada que contienen un atributo de categoría. A continuación, se ahorra su contenido html y su categoría de dos matrices independientes (pero en el mismo lugar.

A continuación se borra todos los divs bajo el div de entrada.

Por último, se pasa a través de sus categorías en el orden se especifica en la matriz y anexa los divs juego de niños en el orden correcto.

la sección de bucle para

@eyelidlessness hace un buen trabajo de explicar para los lazos, pero también va a tomar un golpe en en el contexto de este código.

La primera línea:

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

significa que el código que sigue (todo dentro de los corchetes {code}) se repite un número de veces.Aunque el formato parece arcaica (y sorta es) que dice:

  1. crear una variable de número llamado i y la pusieron igual a cero
  2. Si esa variable es menor que el número de elementos de la matriz category_sort_order, a continuación, ¿Qué hay en los corchetes
  3. Cuando los corchetes terminan, agregue uno a la variable i (i ++ significa agregar uno)
  4. Luego repite los pasos dos y tres hasta que finalmente sea más grande que el número de categorías en esa matriz.

A.K.A lo que esté entre paréntesis se ejecutará una vez para cada categoría.

Pasando a ... para cada categoría, se invoca otro ciclo. Este:

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

recorre todas las categorías de los divs que acabamos de eliminar de la pantalla.

Dentro de este ciclo, la instrucción if comprueba si alguno de los divs de la pantalla coincide con la categoría actual. Si es así, se agregan, si no, el ciclo continúa buscando hasta que pasa por cada div.

+0

Gracias por su ayuda. Soy un principiante de JavaScript y aunque entiendo la primera parte de su código, estoy desconcertado por la segunda parte. ¿Para qué son las líneas i = 0 y j = 0? Los veo mucho y no puedo entender. Gracias de nuevo. – lightyrs

+0

hnovic, esas son variables de iterador. Corresponden a las teclas numéricas del 'Array' que iteran. Un bucle 'for' (típicamente) toma como primer enunciado una clave inicial, su segundo enunciado una clave final, y su enunciado final una instrucción para pasar de la clave inicial a la clave final (típicamente' i ++ 'o' i-- '). – eyelidlessness

+0

Esto tiene el beneficio de no manipular el dom más de lo necesario, pero sí utiliza html en línea que es un poco desagradable, especialmente cuando las cosas comienzan a cambiar. –

1

Pensé que este era un problema realmente interesante, aquí hay una solución de clasificación fácil, pero no increíblemente efectiva que se me ocurrió.

Puede ver la página de prueba en jsbin aquí: 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); 

Tenga en cuenta que la setTimeout podría no ser necesario, pero sólo se siente más seguro. Tu llamada.

Probablemente pueda limpiar algo de rendimiento almacenando una referencia al padre y solo obteniendo hijos cada vez, en lugar de volver a ejecutar el selector. Aunque me iba por la simplicidad. Debe llamar al selector cada vez, porque el orden cambia de una manera y no estoy almacenando una referencia al padre en ninguna parte.

+0

Esto también colocará las categorías que no se encuentran en el conjunto de orden de clasificación al principio de la lista. Si lo desea al final, busque -1 en la función $ .inArray. –

5

Agregar (o anteponer) los nodos DOM de nuevo en realidad los ordenará en el orden que desee.

Usando jQuery, solo tiene que seleccionarlos en el orden que desee y agregarlos (o anteponerlos) a su contenedor nuevamente.

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

Lo sentimos, perdidas que quería eliminar nodos no en la lista de categorías. Esta es la versión corregida:

// 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. 
+0

Gracias por su ayuda. ¿¡Como funciona esto!? Puede usted explicar por favor. Gracias de nuevo – lightyrs

+0

buen uso de 'map()'. El último elemento de la matriz debería ser 'download' aunque :) –

+0

Me gusta. Es una solución muy elegante. – Borgar

0

Es parece bastante directa a utilizar el método sort para éste:

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'); 

Si le sucede a estar usando una versión antigua de jQuery (1.2) que no tiene el método sort, puede agregar con esto:

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

Sólo nota,

Puesto que no jQuery 1.3.2 clasificación es sencilla y sin ningún plugin como:

$('#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 
} 

Esto ordenará todos los div que son hijos del elemento con id = "input".

+0

esta solución funciona perfectamente bien – lamarant

Cuestiones relacionadas