Implementieren von HTML5 Drag & Drop

Eine der neuen Funktionen in HTML5 ist das native Drag & Drop. Überraschenderweise wurde in Internet Explorer seit Version 5.5 natives Drag & Drop unterstützt. Tatsächlich basiert die HTML5-Implementierung auf der Unterstützung von IE. Im heutigen Tutorial wird gezeigt, wie Sie das native Drag & Drop implementieren, um eine einfache Warenkorb-Oberfläche zu erstellen.


Schritt 0. Was machen wir?

Folgendes bauen wir: Es ist ein grundlegender Einkaufswagen mit einer Produktleiste und einer Wagenleiste. Um ein Produkt zu "erwerben", können Sie es vom Panel in den Warenkorb ziehen. Wir behalten die Menge im Auge und entfernen Artikel aus dem Produktbereich, wenn sie nicht vorrätig sind.

Beachten Sie, dass wir hier keinen Einkaufswagen erstellen. Wir werden heute nicht mit Server-Gütern arbeiten. Dies ist nur das Frontend. Der Punkt ist HTML5 Drag & Drop.


Schritt 1. Das HTML

Natürlich fangen wir mit dem HTML an. Hier ist unsere Schale:

     Drag & Drop-Einkaufswagen        

Ziemlich einfach: Wir verknüpfen zu einem Stylesheet und zu jQuery. Wir verwenden nur jQuery für die einfache Ereignisbehandlung und DOM-Manipulation. das Drag & Drop wird nativ sein. Wir stehen hier jedoch vor einer Mauer, da das Ereignisobjekt durch das Ziehen und Ablegen von HTML5 einige Eigenschaften hinzugefügt wird. JQuery verwendet das Standardereignisobjekt nicht. Es erstellt seine eigenen, um Probleme mit Ereignisobjekten auszugleichen. Aus diesem Grund erhalten wir die speziellen Eigenschaften mit dem Ereignisobjekt von jQuery nicht. Aber mach dir keine Sorgen; Dafür gibt es ein Plugin. Wir ziehen das native Drag & Drop an, damit alles funktioniert. Zum Schluss fügen wir unser Skript hinzu: dragdrop.js.

Jetzt können wir unsere Produktliste hinzufügen. Für Produktbilder verwende ich Symbole aus dem von SvenVath erstellten Apple Icon Superpack. (Ich habe die Icons mit einfacheren Namen umbenannt und auf 180px verkleinert.)

Hinzufügen ul # Produkte als erstes Kind im Körper. Sobald Sie das getan haben, prüfen wir den ersten Listeneintrag:

 
  • iMac

    Preis: 1199,00 US-Dollar

    Menge: 10

  • Wir haben einen Listeneintrag mit einem Anker herausgeholt; Beachten Sie, dass jedes Ankerelement eine Klasse von hat Artikel (wichtig, wenn wir zum CSS gelangen) und eine benutzerdefinierte ID (wichtig, wenn wir zum JavaScript gelangen). Dann hat der Anker auch die draggable = "true" Attribut; Dies sollte alles sein, um das Element ziehbar zu machen (wir werden bald ein paar Einschränkungen sehen). Wir verwenden hier ein Ankertag, damit Sie etwas für Browser ohne native Drag & Drop-Unterstützung tun können (obwohl wir das hier nicht tun werden). Dann haben wir das Produktbild und ein Div mit der Produktinfo. Und ja, es ist notwendig, den Preis und die Menge mit einzuwickeln Spanne

    Hier sind die restlichen Elemente der Liste:

     
  • iPhone

    Preis: 199,00 $

    Menge: 16

  • Apple TV

    Preis: 299,00 US-Dollar

    Menge: 9

  • Kino-Anzeige

    Preis: 899,00 US-Dollar

    Menge: 4

  • Ipod Nano

    Preis: 149,00 $

    Menge: 20

  • Macbook

    Preis: 1199,00 US-Dollar

    Menge: 13

  • Mac Mini

    Preis: 599,00 $

    Menge: 18

  • Es gibt ein letztes Stück HTML: den Warenkorb:

     

    Einkaufswagen

      Gesamt: $0,00


      Lassen Sie sich hier in den Warenkorb legen

      Und das ist unser HTML!


      Full Screencast



      Schritt 2. Das CSS

      Idealerweise sollten Sie für ein Element, das Sie ziehen können, nur dieses Attribut auf true setzen können. Es gibt jedoch mehr dazu. Damit alles richtig funktioniert, müssen Sie einige Dinge in CSS einstellen. Denken Sie sich zunächst Folgendes an: Was bewirkt das Klicken und Ziehen bei "normalen" (undraggierbaren) Elementen? Normalerweise wird Text ausgewählt. Dann möchten wir sicherstellen, dass wir das Element ziehen und nicht nur den Inhalt. Um damit umgehen zu können, müssen Sie folgendes CSS verwenden:

       [draggable = true] -moz-user-select: keine; -webkit-user-select: keine; -webkit-user-drag: Element; 

      Für unsere Bequemlichkeit legt das native Drag & Drop-Plugin, das wir verwenden, diese Eigenschaften für uns fest, sodass wir sie weglassen können, wenn wir möchten. Wir werden dies jedoch tun:

       [draggable = true] Cursor: bewegen; 

      Beginnen wir mit dem Styling:

       html Höhe: 100%;  body background: #ececec; Marge: 0; Polsterung: 0; Schriftart: 13px / 1,5 Helvetica, Arial, San-Serif; Höhe: 100%;  h1, h2 text-align: center;  h2 position: absolut; unten: 20px; Farbe: #fff; Textschatten: 0 0 10px rgba (0, 0, 0, 0,75); Anzeige: keine;  p Marge: 0; 

      Da wir keinen vollständigen Reset verwenden, ist hier unser Pseudo-Reset. Es sollte alles ziemlich selbsterklärend sein. Wir stellen die Höhe auf 100% ein html und Karosserie Elemente, weil wir wollen #Wagen die gesamte Höhe des Bildschirms sein; Dazu muss für jedes übergeordnete Element die Höhe auf 100% festgelegt werden. Beachten Sie auch, dass wir mit rgba die Schattenfarbe einstellen. Wenn ein Browser dies nicht unterstützt, wird kein Schatten auf der angezeigt h2. Und wir verstecken das h2 indem man es einstellt Anzeige: keine. Denken Sie daran, das h2 sagt "Zum Ablegen hier in den Warenkorb legen", damit wir es einblenden, wenn das Ziehen beginnt, und ausblenden, wenn das Ziehen endet.

      Weiter zu unserer Produktliste…

       #products float: left; Listenstil: keine; Breite: 65%; Polsterung: 0;  #products li display: inline; 

      Wieder ziemlich offensichtlich. Das Wichtigste in diesem Snippet ist, dass die Listenelemente inline angezeigt werden. Da setzen wir uns ein Bildschirmsperre; Schwimmer: links Auf den Ankern gibt der IE den Listenelementen einen "Treppenstufen" -Effekt. Wir können diesen Fehler durch Einstellen umgehen Anzeige: Inline auf dem übergeordneten Element des Ankers.

      Wenn wir von den Ankern sprechen, wollen wir sie als nächstes gestalten.

       .item Anzeige: Block; Schwimmer: links; Breite: 180px; Höhe: 180px; Marge: 10px; Grenze: 1px fest # 494949; Text ausrichten: Mitte; Textdekoration: keine; Farbe: # 000; Überlauf versteckt;  .item img border: 0; Marge: 10px auto; Breite: 160px; Höhe: 160px;  .item div background: rgb (0, 0, 0); Hintergrund: rgba (0, 0, 0, 0,5); Position: relativ; unten: 69px; Farbe: # f3f3f3; Polsterung: 5px 0; Anzeige: keine; 

      Jeder Anker wird als 180x180px-Box gestaltet. Dieses wird mit dem Produktbild gefüllt. Die Produktinfo wird über dem Bild am unteren Rand des Quadrats positioniert. Beachten Sie, dass wir für moderne Browser eine Hintergrundfarbe festlegen und dann zurücksetzen müssen, da IE RGBa nicht unterstützt. Wir setzen ein Anzeige: keine In diesem Info-Div können wir es ein- und ausblenden, wenn der "Kunde" ein- bzw. ausgeschaltet wird.

      Alles, was noch zu gestalten ist, ist der Einkaufswagen. Wir werden es uns hier ansehen, aber denken Sie daran, dass die Listenelemente später von jQuery eingefügt werden, so dass dies noch nicht angezeigt wird.

       #cart float: right; Hintergrundfarbe: #ccc; Breite: 25%; Polsterung: 0 5%; Höhe: 100%;  #cart ul padding: 0;  #cart li list-style: none; Rand unten: 1px fest # 494949; Polsterung: 5px;  #cart .quantity font-weight: fett; Polsterung rechts: 10px; Rand rechts: 10px; Rand rechts: 1px fest # 494949; Anzeige: Inline-Block; Breite: 15px; Textausrichtung: rechts;  #cart .price float: right;  #total float: right; 

      Elemente mit den Klassen Menge und Preis wird innerhalb der dynamisch eingefügten Listenelemente sein.

      Das war's für CSS. Bevor wir zum Star dieser Show übergehen, werfen wir einen Blick auf unsere bisherigen Arbeiten.



      Schritt 3. Das JavaScript

      Wir haben es zum JavaScript geschafft; laut dem HTML5-Arzt:

      HTML 5 DnD basiert auf der ursprünglichen Implementierung von Microsoft, die bereits als Internet Explorer 5 verfügbar war! Wird derzeit von IE, Firefox 3.5 und Safari 4 unterstützt.

      Hier eine Liste der Ereignisse, die HTML5 per Drag & Drop bietet:

      • ziehen
      • Dragstart
      • drüber ziehen
      • Dragenter
      • dragleave
      • Dragend
      • fallen

      Wir werden nicht alle davon verwenden, aber wir werden sehen, wie die meisten von ihnen funktionieren.

      Zuerst arbeiten wir mit unseren Produkten:

       $ ('. item') .bind ('dragstart', Funktion (evt) evt.dataTransfer.setData ('text', this.id); $ ('h2'). fadeIn ('fast');) .hover (function () $ ('div', this) .fadeIn ();, function () $ ('div', this) .fadeOut (););

      Wir beginnen damit, alle Gegenstände zu packen. dann binden wir eine funktion an die Dragstart Veranstaltung; Dieses Ereignis wird ausgelöst, wenn wir das Ereignis ziehen. Wenn wir ein Objekt ziehen, müssen wir zunächst einige Daten festlegen. Wenn keine Daten festgelegt sind, lässt firefox das Element nicht ziehen. Das Ziehen von Ereignissen ist speziell eine Objekteigenschaft für das Ereignisobjekt Datentransfer; Wir werden zwei Methoden dieser Eigenschaft verwenden: setData und Daten empfangen. Hier benutzen wir die setData Methode, die zwei Parameter benötigt: ein Datenformat und die Daten. Wir verwenden den Datentyp 'Text'. Dann legen wir die Daten als ID des Elements fest, das der Benutzer zieht. Dann werden wir das einblenden h2 als Aufforderung an den Kunden.

      Wir verwenden auch die jQuery-Hover-Methode, um die Produktinformationen einzublenden, wenn Sie mit der Maus darüber fahren und sie ausblenden, wenn Sie mit der Maus ausfahren. Beachten Sie, dass wir den Knoten, den wir als Kontext anzeigen, übergeben, sodass wir nur das Div des entsprechenden Produkts erhalten.

      Fügen wir nun die Event-Handler zum hinzu #Wagen. Wir werden auf der handeln drüber ziehen, Dragenter, und fallen Veranstaltungen:

       $ ('# cart') .bind ('dragover', Funktion (evt) evt.preventDefault ();) .bind ('dragenter', Funktion (evt) evt.preventDefault ();) .bind ( 'drop', Funktion (evt) );

      Damit das Drop-Ereignis ausgelöst werden kann, müssen wir die Standardaktion für das Ereignis abbrechen drüber ziehen Veranstaltung; Dieses Ereignis wird fortlaufend für das Ablageziel ausgelöst, wenn ein ziehbares Element darüber gezogen wird. Nur für den IE müssen wir die Standardaktion für Dragenter Ereignis, das nur auftritt, wenn das ziehbare Element das Ablageziel erreicht. Die Gründe für das Annullieren der Standardaktion sind etwas neblig; um ehrlich zu sein, ich verstehe sie nicht wirklich. Folgendes sagt Remy Sharp dazu:

      Dem Browser wird gesagt, dass dieses Element das Drag-Ereignis ist, gegen das der Drag-Event abgefangen werden soll. Andernfalls führt der Browser seine normale Drag-Aktion aus. Durch Abbruch des Ereignisses wird dem Browser also mitgeteilt, dass dies das Element ist, das sich bewegen sollte.

      Ich sollte beachten, dass jQuery uns hier ein bisschen hilft. Normalerweise müssten wir auch falsch zurückgeben es funktioniert im IE; jQuery ist jedoch behoben Standard verhindern tut das für uns.

      Jetzt die fallen Veranstaltung; Auch dieses Ereignis wird auf das Abwurfziel abgefeuert div # cart in unserem Fall. Bevor wir uns die Funktion ansehen, wollen wir darüber sprechen, was diese Funktion tun soll:

      • Holen Sie sich das Produkt, das wir fallen gelassen haben
      • Wenn das Produkt bereits gekauft wurde, fügen Sie der gekauften Menge einen hinzu. Andernfalls fügen Sie den Artikel zum Warenkorb hinzu
      • die Produktmenge verringern
      • den Gesamtpreis aktualisieren

      Hier ist der erste Teil:

       var id = evt.dataTransfer.getData ('text'), item = $ ('#' + id), cartList = $ ("# cart ul"), total = $ ("# total span"), Preis = $ ('p: eq (1) span', item) .text (), prevCartItem = null, notInCart = (function () var lis = $ ('li', cartList), len = lis.length, i; (i = 0; i < len; i++ )  var temp = $(lis[i]); if (temp.data("id") === id)  prevCartItem = temp; return false;   return true;  ()), quantLeftEl, quantBoughtEl, quantLeft;

      Ich kenne; Es gibt viele Variablen, aber wir werden sie alle verwenden. Lass uns über sie gehen; Zuerst erhalten wir die Textdaten, die wir mit dem Ereignis übertragen haben. Wir haben die ID so übertragen, weil das Ereignisobjekt nichts enthält, das uns sagt, welches Element auf unser Ziel gefallen ist. Wir erhalten die ID und verwenden sie, um das gelöschte Element zu finden. Als Nächstes erhalten Sie die Warenkorbliste und die gesamte Preisspanne. Dann erhalten wir den Preis des einzelnen Artikels. Wir wissen, dass es sich um den Bereich innerhalb des zweiten Absatzes des Elements handelt, sodass wir das Element als Kontextparameter verwenden können. Wir werden uns setzen prevCartItem für den Moment auf null, aber wir werden es verwenden, um zu sehen, ob der in den Warenkorb gezogene Artikel bereits vorhanden ist. Der Wert von notInCart ist eine selbstaufrufende anonyme Funktion. Es wird jedes Listenelement in der cartList durchlaufen (wiederum verwenden wir den context-Parameter) und prüfen, ob die data-Eigenschaft angezeigt wird Ich würde ist das gleiche wie die Variable Ich würde. Um dies zu verstehen, müssen Sie wissen, dass wir, wenn wir dem Warenkorb Listenelemente hinzufügen, die jQuery verwenden Daten Methode, um die Produkt-ID des Geschäfts mit dem Artikel festzulegen. In dieser Funktion suchen wir nach einem Listenelement mit den richtigen Daten. Wenn wir einen finden, ist der Artikel bereits im Warenkorb, und so setzen wir notInCart zu falsch; Ist sie nicht im Warenkorb, setzen wir die Variable auf true. Zum Schluss verwenden wir quantLeftEl, quantBoughtEl, und quantLeft bei der Aktualisierung der Mengen.

      Nun zu etwas Aktion:

       $ ("h2"). fadeOut ('fast'); if (notInCart) prevCartItem = $ ('
    • ', text: $ (' p: first ', item) .text (), data: id: id). prepend ($ ('', ' class ':' Quantity ', Text:' 0 ')).. voranstellen ($ ('', ' class ':' price ', Text: price)). appendTo (cartList);
    • Zuerst werden wir das ausblenden h2 Prompt. Wenn sich der Artikel nicht im Warenkorb befindet, fügen wir ihn dem Warenkorb hinzu. Dazu erstellen wir ein Listenelement. Dann können wir ein Objektliteral als zweiten Parameter übergeben, um die Eigenschaften unseres neuen Listenelements festzulegen. Wir setzen den Text auf den Produktnamen. das kommt aus dem ersten Absatz in der Produktposition. Dann setzen wir die Daten, über die wir oben gesprochen haben.

      Als Nächstes fügen wir diesem Listenelement eine Zeitspanne vor; wir geben ihm eine Klasse von 'Quantität' (vergessen Sie nicht, Klasse in Anführungszeichen zu setzen, da es ein reserviertes Wort ist) und setzen Sie den Text auf Null; Ja, ich weiß, es sollte eine sein, da sie den Artikel gerade in den Warenkorb gelegt haben, aber wir werden das später erhöhen ... und Sie werden sehen, warum.

      Dem Listeneintrag wird ein weiterer Zeitraum vorangestellt, diesmal für den Preis. Wir werden den Preis nach rechts bewegen, daher erscheint es logisch anhängen es; aber das würde einen Float-Fehler im IE verursachen; Die Spanne würde sich rechts und unterhalb des Listenelements bewegen.

      Zum Schluss fügen wir den Listeneintrag der Einkaufswagenliste hinzu.

      Der letzte Teil dieser Funktion wird ausgeführt, unabhängig davon, ob sich der Artikel bereits im Warenkorb befindet oder nicht:

       quantLeftEl = $ ('p: last span', item); quantLeft = parseInt (quantLeftEl.text (), 10) - 1; quantLeftEl.text (quantLeft); quantBoughtEl = $ ('.Quantität', prevCartItem); quantBoughtEl.text (parseInt (quantBoughtEl.text (), 10) + 1); if (quantLeft === 0) item.fadeOut ('fast'). remove ();  total.text ((parseFloat (total.text (), 10) + parseFloat (price.split ('$') [1])). toFixed (2)); evt.stopPropagation (); falsch zurückgeben;

      Zuerst erhalten wir die Menge aus dem Produktartikel. Dies ist die verbleibende Menge, wenn der Kunde den Artikel in den Warenkorb gezogen hat. Wir bekommen dann die Menge, die wirklich übrig ist. Aber das ist eine Zeichenfolge, also verwenden wir die native Funktion parseInt Um es in eine Zahl umzuwandeln (verwenden Sie 10 als Basis, um sicherzustellen, dass wir eine Dezimalzahl erhalten) und ziehen Sie eine davon ab. Dann setzen wir die Menge mit jQuery zurück Text Methode.

      Als Nächstes erhalten wir die Menge, die der Benutzer gekauft hat. Dies ist das Element mit einer Klasse von 'Quantität'; wir nehmen das prevCartItem als Kontext; Dies funktioniert, wenn der Artikel bereits im Warenkorb war, prevCartItem wurde in dieser anonymen Funktion eingestellt; Wenn es nicht im Einkaufswagen war, haben wir es beim Erstellen des Warenkorbeintrags festgelegt. Wir können den Textwert dann festlegen, indem wir den aktuellen Wert abrufen, in eine Zahl konvertieren und einen Wert hinzufügen.

      Was passiert, wenn die Restmenge null ist? Wenn es null ist, blenden wir das Element aus und entfernen es.

      Schließlich müssen wir den Gesamtpreis aktualisieren. Wir haben die gesamte Spanne, sodass wir den Text einfach zurücksetzen können. Was wir tun, ist, den aktuellen Text abzurufen und ihn in eine Zahl umzuwandeln (diesmal verwenden wir) parseFloat um die Cents zu behalten), das Dollarzeichen vom Preis getrennt und in eine Zahl umgewandelt und zwei Werte addiert. Zum Schluss verwenden wir toFixed um sicherzustellen, dass wir immer den korrekten cents-wert anzeigen.

      Schließlich wollen wir das nicht fallen drop event to bubble, also stoppen wir die Verbreitung und geben false zurück;


      Schritt 4. Das abgeschlossene Projekt

      Gute Arbeit, wir sind fertig. Hier ist ein Schuss von unserem Wagen in Aktion:


      Wenn Sie herausfinden möchten, was die anderen Drag & Drop-Ereignisse tun, fügen Sie dies dem Skript hinzu:

       $ ('# cart'). bind ('dragleave', function (evt) console.log ('dragleave');); $ ('. item') .bind ('Dragend', Funktion (evt) console.log ('Dragend');) .bind ('Dragstart', Funktion (Evt) Console.log ('Dragstart') ;) .bind ('ziehen', function (evt) console.log ('ziehen'););

      Das native HTML5-Drag-and-Drop-Verfahren ist zwar möglicherweise noch nicht vollständig bereit (Opera unterstützt es nicht), aber es ist auf jeden Fall spannend zu sehen, wohin die Dinge laufen!