Aparte de algunos trucos esotéricos que involucran cosas como el controlador de cambio de tamaño en las áreas de texto, los elementos que se pueden arrastrar son territorio de JavaScript en la web. Por ejemplo, haga clic en el elemento, mantenga presionado el botón del mouse, arrastre el cursor del mouse, el elemento se arrastra con el mouse, suelte el botón del mouse para liberar el elemento. O los equivalentes táctiles. Afortunadamente, este es un territorio bien pisado. Las herramientas probadas por el tiempo como jQuery UI ofrecen Draggable (y otros métodos similares) para facilitar esto.
Pero recientemente, al tratar de lograr cierto efecto (vea el título de este artículo), no pude lograr que jQuery UI lo hiciera como yo quería. Pero lo hice y así es como.
Intentaba recrear el efecto en la barra lateral de Keynote, donde puedes arrastrar para reorganizar las diapositivas. Aquí está el efecto final:
Puede acercarse mucho con una configuración de interfaz de usuario de jQuery realmente básica. Estamos usando el método Ordenable aquí. Esto es específicamente para ordenar listas, que es lo que estamos haciendo, que es un poco como usar Draggable y Droppable.
$(".all-slides").sortable({
axis: "y",
revert: true,
scroll: false,
placeholder: "sortable-placeholder",
cursor: "move"
});
En algunos HTML básicos como este:
<div class="all-slides">
<div class="slide">Slide</div>
<div class="slide">Slide</div>
<div class="slide">Slide</div>
<!-- etc -->
El “marcador de posición” en la configuración es un elemento (con el nombre de clase provisto) que se inserta entre las diapositivas donde esa diapositiva caería si soltara el botón del mouse en este momento. Puedes diseñarlo como quieras con CSS, así que hice que se viera como la línea azul a la izquierda como Keynote.
El problema aquí es que no conseguimos ese efecto de “empujar fuera del camino” que buscamos. El marcador de posición aparece inmediatamente. Originalmente traté de resolverlo usando una animación @keyframes para expandir la altura del marcador de posición de 0 a la altura de la diapositiva y luego quedarme allí con el modo de relleno. Eso funciona para la apariencia del marcador de posición, pero jQuery UI simplemente extrae ese marcador de posición del DOM cuando desaparece, lo que no permitió una salida elegante.
Así que un truco más profundo estaba en orden. Afortunadamente, después de lamentar el problema en Twitter, AJ Kandy Encontré un ejemplo útil. haciendo justo lo que necesitaba.
Ten paciencia conmigo, esto se vuelve un poco complicado:
- Recorrer todas las diapositivas
- Crear un duplicado de cada diapositiva
- Coloque la diapositiva directamente encima del original
- Esconderlo
- Guarde una referencia a la diapositiva de la que se duplicó
Luego inicia el método Sortable solo en los originales. Luego, cuando comience a arrastrar una diapositiva:
- Ocultar todas las diapositivas originales
- Revelar los clones
- A medida que arrastra, los originales se reorganizarán de forma invisible
- Después de hacer eso, anime los clones a esas nuevas posiciones.
Cuando el arrastre se detiene:
- Asegúrese de que todos los clones estén en la posición final correcta
- Cambia la visibilidad de nuevo, revelando los originales.
Me tomó una buena cantidad de tiempo entender y jugar para hacerlo bien. En mi ejemplo, uso elementos psuedo para numerar las diapositivas, por lo que también hay un poco de código para eso. Aquí está todo junto.
$(".slide").each(function(i) {
var item = $(this);
var item_clone = item.clone();
item.data("clone", item_clone);
var position = item.position();
item_clone
.css({
left: position.left,
top: position.top,
visibility: "hidden"
})
.attr("data-pos", i+1);
$("#cloned-slides").append(item_clone);
});
$(".all-slides").sortable({
axis: "y",
revert: true,
scroll: false,
placeholder: "sortable-placeholder",
cursor: "move",
start: function(e, ui) {
ui.helper.addClass("exclude-me");
$(".all-slides .slide:not(.exclude-me)")
.css("visibility", "hidden");
ui.helper.data("clone").hide();
$(".cloned-slides .slide").css("visibility", "visible");
},
stop: function(e, ui) {
$(".all-slides .slide.exclude-me").each(function() {
var item = $(this);
var clone = item.data("clone");
var position = item.position();
clone.css("left", position.left);
clone.css("top", position.top);
clone.show();
item.removeClass("exclude-me");
});
$(".all-slides .slide").each(function() {
var item = $(this);
var clone = item.data("clone");
clone.attr("data-pos", item.index());
});
$(".all-slides .slide").css("visibility", "visible");
$(".cloned-slides .slide").css("visibility", "hidden");
},
change: function(e, ui) {
$(".all-slides .slide:not(.exclude-me)").each(function() {
var item = $(this);
var clone = item.data("clone");
clone.stop(true, false);
var position = item.position();
clone.animate({
left: position.left,
top: position.top
}, 200);
});
}
});
Y la demostración:
Vea el Reorganizador de diapositivas de lápiz como Keynote de Chris Coyier (@chriscoyier) en CodePen.
Característica de bonificación: las diapositivas adquieren una clase cuando son drogas que pulsan su tamaño, como en Keynote.
Otras opciones
David DeSandro tiene algunos proyectos de los que quizás haya oído hablar sobre la reorganización de cajas en la web, como Masonry e Isotope. También tiene uno llamado Packery que usa un algoritmo para empacar cajas en espacios. Junto con otro proyecto suyo, Dragabilly, puedes crear el mismo efecto en el que arrastrar un elemento aparta a los demás. La naturaleza de un solo eje de nuestra demostración es un trabajo fácil para ella.
David bifurcó mi demostración y la hizo funcionar con esas herramientas, y es un poco menos código:
Vea el Reorganizador de diapositivas de lápiz como Keynote, con Packery y Draggabilly de Chris Coyier (@chriscoyier) en CodePen.
Luke Underwood también lo intentó, apoyando trozos de diferentes tamaños:
Vea Pen jQuery Sortable con transiciones y soporte de altura variable por Luke Underwood (@Snarkie3) en CodePen.