Abgesehen von ein paar esoterischen Tricks mit Dingen wie dem Größenänderungsgriff von Textbereichen, sind ziehbare Elemente im Web Domäne von JavaScript. Z.B. Element anklicken, Maustaste gedrückt halten, Mauszeiger bewegen, Element folgt der Maus, Maustaste loslassen, um das Element loszulassen. Oder die Touch-Äquivalente. Glücklicherweise ist dies gut erforschtes Terrain. Zeitgeprüfte Werkzeuge wie jQuery UI bieten Draggable (und andere ähnliche Methoden), um dies zu vereinfachen.
Aber kürzlich habe ich bei dem Versuch, einen bestimmten Effekt zu erzielen (siehe Titel dieses Artikels), festgestellt, dass jQuery UI ihn nicht ganz so machte, wie ich wollte. Aber ich habe es geschafft, und hier ist, wie.
Ich habe versucht, den Effekt in der Seitenleiste von Keynote nachzubilden, wo man per Drag & Drop Folien neu anordnen kann. Hier ist der fertige Effekt

Man kommt mit einigen sehr grundlegenden jQuery UI-Konfigurationen sehr nahe heran. Wir verwenden hier die Sortable-Methode. Diese ist speziell für das Sortieren von Listen gedacht, was wir tun, und ähnelt der Verwendung von sowohl Draggable als auch Droppable.
$(".all-slides").sortable({
axis: "y",
revert: true,
scroll: false,
placeholder: "sortable-placeholder",
cursor: "move"
});
Auf grundlegendem HTML wie diesem
<div class='all-slides'>
<div class='slide'>Slide</div>
<div class='slide'>Slide</div>
<div class='slide'>Slide</div>
<!-- etc -->
Der "Platzhalter" in der Konfiguration ist ein Element (mit dem angegebenen Klassennamen), das zwischen die Folien eingefügt wird, wo die Folie landen würde, wenn Sie die Maustaste gerade loslassen würden. Sie können dies mit CSS beliebig gestalten, also habe ich es wie die blaue Linie links bei Keynote aussehen lassen.

Das Problem hierbei ist, dass wir nicht den gewünschten "aus dem Weg schieben"-Effekt erzielen. Der Platzhalter erscheint sofort. Ursprünglich habe ich versucht, das Problem durch eine @keyframes-Animation zu lösen, um die Höhe des Platzhalters von 0 auf die Folienhöhe zu erweitern und dort mit fill-mode zu verharren. Das funktioniert für das Aussehen des Platzhalters, aber jQuery UI reißt diesen Platzhalter aus dem DOM, wenn er verschwindet, was keinen anmutigen Abgang ermöglichte.
Also war tiefergehende Trickkiste gefragt. Glücklicherweise hat AJ Kandy, nachdem er sich auf Twitter über die Schwierigkeit beklagt hatte, ein praktisches Beispiel gefunden, das genau das tut, was ich brauchte.
Gedulden Sie sich, das wird etwas kompliziert
- Schleife durch alle Folien
- Erstelle eine Kopie jeder Folie
- Positioniere die Kopie direkt über dem Original
- Verstecke sie
- Speichere eine Referenz auf die Folie, von der sie kopiert wurde
Dann initiierst du die Sortable-Methode nur auf den Originalen. Dann, wenn du eine Folie ziehst
- Verstecke alle Original-Folien
- Zeige die Kopien an
- Während du ziehst, werden die Originale unsichtbar neu angeordnet
- Nachdem sie das getan haben, animiere die Kopien zu diesen neuen Positionen
Wenn das Ziehen endet
- Stelle sicher, dass alle Kopien an der richtigen Endposition sind
- Vertausche wieder die Sichtbarkeit, zeige die Originale an
Es dauerte eine ganze Weile, bis ich das verstanden und richtig getüftelt hatte. In meinem Beispiel verwende ich Pseudo-Elemente, um die Folien zu nummerieren, daher gibt es auch dafür etwas Code. Hier ist alles zusammen.
$(".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);
});
}
});
Und die Demo
Sieh dir den Pen Folien-Neuordner wie Keynote von Chris Coyier (@chriscoyier) auf CodePen an.
Bonus-Feature: Die Folien erhalten eine Klasse, wenn sie gezogen werden, was ihre Größe pulsieren lässt, wie bei Keynote.
Andere Optionen
David DeSandro hat einige Projekte, von denen Sie vielleicht schon gehört haben, die sich alle mit dem Neuordnen von Boxen im Web befassen, wie Masonry und Isotope. Er hat auch ein Projekt namens Packery, das einen Algorithmus verwendet, um Boxen in Räume zu packen. Zusammen mit einem weiteren seiner Projekte, Dragabilly, können Sie denselben Effekt erzielen, bei dem das Ziehen eines Elements andere aus dem Weg schiebt. Die Einachsen-Natur unserer Demo ist für sie leichte Arbeit.
David hat meine Demo gegabelt und sie mit diesen Tools zum Laufen gebracht, und das mit deutlich weniger Code
Sieh dir den Pen Folien-Neuordner wie Keynote – mit Packery und Draggabilly von Chris Coyier (@chriscoyier) auf CodePen an.
Luke Underwood hat sich auch daran versucht und unterstützt unterschiedlich große Elemente
Sieh dir den Pen jQuery Sortable mit Übergängen und variabler Höhenunterstützung von Luke Underwood (@Snarkie3) auf CodePen an.
Oooh, das habe ich auch gebaut :) — Slip.JS (ohne jQuery)
Das nervige war die Interaktion von Scrolling und Touch-Events – wenn die Ansicht scrollbar sein soll, darfst du das Scrollen bei Touch nicht blockieren, sondern musst eine Weile warten, um die Fingerbewegung zu messen. Leider erlauben Browser nur dem allerersten touchmove-Event, das Scrollen zu blockieren, so dass es zu spät ist, wenn du merkst, dass du kein Scrollen willst :-(
Es sieht sehr schön und poliert aus, aber ich hatte in FF 27 ein komisches Verhalten beim Ziehen und Scrollen im ersten Beispiel. Die Liste blieb fixiert und das gezogene Element scrollte. Ich bin mir nicht sicher, ob das das beabsichtigte Verhalten ist oder wie man es behebt, ich wollte es nur erwähnen.
Ich habe das sowohl in Chrome 32 als auch in Firefox 23 ausprobiert, und alle anderen Folien verschwanden, während ich die ausgewählte Folie zog. Im
start-Parameter dessortable-Hashes habe ich den ersten CSS-Aufruf in.css("visibility", "visible")geändert und jetzt funktioniert es (wenn auch ohne die sanfte Push-Out-of-Way-Animation). Das Ändern des zweiten CSS von "visible" auf "hidden" führt zu keiner zusätzlichen Änderung.Sind beide Probleme (Verstecken während des Ziehens und keine "Push"-Animation) eine Folge der Nichtverwendung des oben gezeigten CSS? Ich habe nur ein paar schnelle Stile hinzugefügt, um Ihre zu imitieren.
Interessanter Ansatz
Ich persönlich verwende seit jeher Gridster für etwas sehr Ähnliches, und ich finde ihre Methode ziemlich elegant, Sie sollten es sich ansehen (es ist etwas fehlerhaft, wenn Sie etwas tun wollen, wofür es nicht gedacht ist, aber es funktioniert)
Kurz gesagt, sie berechnen die absolute Position aller Elemente und erstellen ein "Pseudo-Gitter" im Speicher und generieren eine Stilvorlage mit der Position jeder Zeile/Spalte. Diese Stile werden dann auf die Elemente angewendet.
Damit ist es einfach, CSS-Animationen zu verwenden, um den gewünschten Push-Effekt zu erzielen
Was soll das letzte (geforkte) tun? Sowohl in Firefox (27) als auch in Chrome (32) sowie IE11 scheint das "gezogene" Element an seiner ursprünglichen Stelle zu bleiben.
Hier ist eine weitere einfachere Implementierung
Demo: http://jsfiddle.net/tovic/85EpZ/
Sie können denselben Effekt erzielen, indem Sie CSS3-Übergänge auf die "top"-Eigenschaft anwenden: http://codepen.io/nuo/pen/CxLek
Gute Arbeit! :)
Vor einiger Zeit war ich frustriert, dass es nur sehr wenige dieser sanften Sortierdinge gab. Die wenigen, die ich finden konnte, basierten alle auf jquery sortable, und es fühlt sich einfach ungelenk an, wie es den Mauszeiger verfolgt und entscheidet, wann Elemente neu angeordnet werden. Ich wollte wirklich das solide Gefühl bekommen, wie man es beim Neuordnen von Dingen auf iOS bekommt. Hier ist mein Versuch: http://pumpula.net/p/smooth-sortable/
Im realen Einsatz gibt es wahrscheinlich keinen großen Unterschied zwischen dieser und den meisten anderen Implementierungen, aber ich bin besessen davon, das Gefühl genau richtig hinzubekommen.
Ich bin kein erfahrener Programmierer, daher ist der Code ein bisschen Spaghetti, aber ich denke, ich habe die "Physik" davon ziemlich gut gelöst. Der Trick ist, die tatsächlichen Objektgrenzen zu verfolgen und nicht den Mauszeiger. (Genau wie das Packery-Beispiel, denke ich) Das Packery-Beispiel hat eine leichte Verzögerung, bis es Elemente neu anordnet. Zur Performance vielleicht? Ich dachte, dass man die Geometrie der Liste beim Drag-Start in ein JS-Objekt messen, dann dieses zur Verfolgung aller verwenden und neue Positionsstile auf die tatsächlichen DOM-Elemente anwenden und CSS-Übergänge die Animation durchführen lassen würde, und das scheint sehr gut zu funktionieren. Es gibt also eine virtuelle Liste, die die ganze Arbeit macht, und eine DOM-Liste, die entsprechend der virtuellen Liste animiert wird.
@Ville Vanninen: Wow, ich bin sehr beeindruckt von Ihrer Arbeit. Das ist sehr schick, flüssig und reaktionsschnell. Tolle Arbeit. Lesezeichen gesetzt.
Sie können eine Folie auf eine andere Folie ziehen, wenn Sie das zweite Beispiel mit einem Telefon verwenden.
Edit: Anscheinend nicht mehr... Es funktionierte heute Morgen nicht, jetzt schon!
Es wäre interessant, dies mit animiertem Inhalt zu verwenden, um eine Playlist zusammenzustellen.
Ich möchte auch Greensock Draggable erwähnen, es ist ziemlich wie die anderen: Touch-Unterstützung usw., aber mit sehr flüssiger Bewegung, und die Premium-Version bietet auch Wurf-Physik.
Es kommt nicht standardmäßig mit Sortierlogik, aber mit dem Callback-System können Sie sie ziemlich einfach implementieren.
Die zweite Demo funktionierte auf meinem Handy :D
Aber es verhält sich seltsam, wenn man ein Element nach oben zu seiner Position zieht. Auch die Animation der gezogenen Folie funktioniert beim ersten Mal. Aber dann nicht mehr.
Hier teste ich mit Chrome mit einem iPhone 5
Die zweite Demo von David funktioniert auf meinem iPhone.
Das letzte Beispiel schlägt in Chrome fehl.
Beim Verschieben eines Elements in die letzte Position wird die Nummerierung der Elemente nicht geändert.
Sehr cool. Ich habe gerade etwas sehr Ähnliches erstellt, allerdings mit Isotope und jQuery UI. Die Grundidee ist, dass man das
start-Event von Sortable verwendet, um ein gezogenes Element aus Isotope zu entfernen, während es bewegt wird, und es dann beimstopwieder zu Isotope hinzufügt und die Elemente neu lädt (was sie in die neue Reihenfolge animiert).Man muss die Elemente nicht duplizieren und kann auch die anderen eingebauten Funktionen von Isotope nutzen (wie Sortierung und Filterung, was Packery nicht kann) ;-)
HAML, SCSS und jQuery JS. Ich musste so lachen... Wir schreiben keine Anleitungen mehr, sondern Beschreibungen dessen, was wir uns vorstellen.
Ich habe mit Alfresco gearbeitet, das YUI-Zeug für diese Art von Verhalten verwendet. Ich bin mir nicht sicher, wie es implementiert wurde, aber ich weiß, dass man Drag & Drop und diese hübschen animierten Sachen darin hatte. Es war YUI 2.6 oder so, haben Sie jemals damit gearbeitet?
Ich habe es fast vollständig mit CSS-Übergängen hinbekommen (und immer noch jQuery sortable verwendet). Während der Sortierung ist die grundlegende HTML-Struktur wie folgt:
Also sollte es einen Übergang aller Folien nach
sortable-placeholdergeben, aber nicht dieui-sortable-helper-Folie einschließen. Das CSS sieht so aus:Dies ist die grundlegende Übergangseinstellung. Aber wir müssen die Sortierung starten/beenden berücksichtigen, bei denen kein Übergang stattfinden sollte. Also füge ich ein wenig JavaScript-Code hinzu, um Klassen umzuschalten. Dieser Teil ist etwas knifflig. Und das Ergebnis ist nicht perfekt.
Hier ist der Demo-Pen.
Haben Sie auch manchmal das Gefühl, dass alles Einfache jetzt schwer ist und alles Schwere jetzt unmöglich? Dieses beklemmende Gefühl habe ich, wenn ich solche Dinge sehe. Oder wenn ich damit gearbeitet habe.
Brillanz, absolute Brillanz, im Beitrag und in den Kommentaren, wo Leute ein kaputtes System zum Tanzen bringen. Zweifellos.
Aber ist das Leben nicht zu kurz, um so hart zu kämpfen, um eine so einfache Animation zu machen?
Ich werde jetzt zu meinem Compiler und meiner Desktop-Software zurückkehren und für all eure Seelen beten.
(Scherzhaft)