2009-10-26 9 views
24

Digamos que tengo la siguiente lista desordenadaMover el elemento al principio de la lista desordenada usando jQuery

<ul> 
<li><a>Hank</a></li> 
<li><a>Alice</a></li> 
<li><a>Tom</a></li> 
<li><a>Ashlee</a></li> 
</ul> 

Lo que estoy buscando es cuando hago clic en Tom, que se mueve (animado y sin arrastrar) a la parte superior de la lista (índice 0).

Ive considerado jquery ordenable, pero no puedo encontrar una manera de activar la parte móvil mediante programación.

Respuesta

17

Se me ocurrió una solución que parece funcionar bastante bien. Es una prueba de concepto, por lo que probablemente tendrá que modificarlo un poco para que funcione mejor para su caso específico. Además, solo lo probé en Firefox, pero no veo ninguna razón por la que esto no funcione en todos los navegadores. De todos modos, aquí está:

<script type="text/javascript"> 
    $(document).ready(function() { 
    $('li').click(function() { 
     // the clicked LI 
     var clicked = $(this); 

     // all the LIs above the clicked one 
     var previousAll = clicked.prevAll(); 

     // only proceed if it's not already on top (no previous siblings) 
     if(previousAll.length > 0) { 
     // top LI 
     var top = $(previousAll[previousAll.length - 1]); 

     // immediately previous LI 
     var previous = $(previousAll[0]); 

     // how far up do we need to move the clicked LI? 
     var moveUp = clicked.attr('offsetTop') - top.attr('offsetTop'); 

     // how far down do we need to move the previous siblings? 
     var moveDown = (clicked.offset().top + clicked.outerHeight()) - (previous.offset().top + previous.outerHeight()); 

     // let's move stuff 
     clicked.css('position', 'relative'); 
     previousAll.css('position', 'relative'); 
     clicked.animate({'top': -moveUp}); 
     previousAll.animate({'top': moveDown}, {complete: function() { 
      // rearrange the DOM and restore positioning when we're done moving 
      clicked.parent().prepend(clicked); 
      clicked.css({'position': 'static', 'top': 0}); 
      previousAll.css({'position': 'static', 'top': 0}); 
     }}); 
     } 
    }); 
    }); 
</script> 

<ul> 
<li><a>Hank</a></li> 
<li><a>Alice</a></li> 
<li><a>Tom</a></li> 
<li><a>Ashlee</a></li> 
</ul> 

Se calcula la diferencia en los desplazamientos entre el LI hecho clic y el primer LI y mueve el hecho clic hasta la parte superior estableciendo su position-relative y animación de la propiedad top. Del mismo modo, calcula cuánto espacio quedó atrás por el LI cliqueado y mueve todos los anteriores en consecuencia. Cuando termina con las animaciones, reorganiza el DOM para que coincida con el nuevo orden y restaura los estilos de posicionamiento.

Espero que ayude!

+0

Guau, que parece muy interesante, definitivamente voy a probar esto. Votado! – Fabian

+0

¿Hay alguna versión que mueva los elementos li por uno? – crosenblum

10

Suponiendo:

<ul id="list"> 
<li><a>Hank</a></li> 
<li><a>Alice</a></li> 
<li><a>Tom</a></li> 
<li><a>Ashlee</a></li> 
</ul> 

a continuación:

$("#list a").click(function() { 
    $(this).parent().before("#list a:first"); 
    return false; 
}); 

Si desea animar a continuación, que es un poco más difícil. Una de las opciones:

$("#list a").click(function() { 
    $(this).parent().slideUp(500).before("#list a:first").slideDown(500); 
    return false; 
}); 

Otra opción:

$("#list a").click(function() { 
    var item = $(this).parent(); 
    var prev = item.prev(); 
    while (prev.length > 0) { 
    item.before(prev); 
    prev = item.prev(); 
    } 
    return false; 
}); 

pero dudo que obtendrá una animación suave de esa manera.

+0

No es exactamente lo que estoy buscando pero supongo que es la mejor opción. Votado arriba. – Fabian

2

Jugué con el violín No Surprises y extendí el código para intercambiar dos conjuntos arbitrarios de elementos (la única restricción es que deben seguirse directamente).

ver aquí: http://jsfiddle.net/ZXYZ3/139/

45

Encontramos este aun más ordenado:

$('li').on('click', function() { 
    $(this).parent().prepend(this); 
});​ 

Live example

+4

y para ir al final: '$ (this) .parent(). Append (this);' –

+0

Y si no lo has adivinado, ve a la parte superior: '$ (this) .parent(). Prepend (esto); ' –

+0

~~ LOVELOVELOVE ~~ – flunder

1

me ocurrió con esta solución: http://jsfiddle.net/FabienDemangeat/TBYWw/

La idea es elegir el índice de la Elemento Li que se moverá y su destino. Si el valor de destino es inferior al índice del elemento li para mover, el efecto se invertirá.

Algunas piezas no son perfectas pero pueden ser un punto de partida.Me inspiré en el fragmento proporcionado por "Sin sorpresas"

La función principal swapLiElements intercambia dos elementos li y la función de devolución de llamada como parámetros permite hacer más de un intercambio fácilmente (see fiddle).

function swapLiElements($northLi, $southLi, isPushingDown, duration, easing, callbackFunction) { 

    var movement = $northLi.outerHeight(); 

    // Set position of the li elements to relative 
    $northLi.css('position', 'relative'); 
    $southLi.css('position', 'relative'); 

    // Set the z-index of the moved item to 999 to it appears on top of the other elements 
    if(isPushingDown) 
     $northLi.css('z-index', '999'); 
    else   
     $southLi.css('z-index', '999'); 

    // Move down the first li 
    $northLi.animate({'top': movement}, { 
     duration: duration, 
     queue: false, 
     easing: easing, 
     complete: function() { 
      // Swap the li in the DOM 
      if(isPushingDown) 
       $northLi.insertAfter($southLi); 
      else 
       $southLi.insertBefore($northLi); 

      resetLiCssPosition($northLi); 
      resetLiCssPosition($southLi); 

      callbackFunction(); 
     } 
    }); 

    $southLi.animate({'top': -movement}, { 
     duration: duration, 
     queue: false, 
     easing: easing, 
    }); 

} 
Cuestiones relacionadas