Draggable Elemente, die andere aus dem Weg schieben

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

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

  1. Schleife durch alle Folien
  2. Erstelle eine Kopie jeder Folie
  3. Positioniere die Kopie direkt über dem Original
  4. Verstecke sie
  5. 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

  1. Verstecke alle Original-Folien
  2. Zeige die Kopien an
  3. Während du ziehst, werden die Originale unsichtbar neu angeordnet
  4. Nachdem sie das getan haben, animiere die Kopien zu diesen neuen Positionen

Wenn das Ziehen endet

  1. Stelle sicher, dass alle Kopien an der richtigen Endposition sind
  2. 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.