Implementere HTML5 Dra og slipp

En av de nye funksjonene i HTML5 er innfødt dra og slipp. Overraskende nok har Internet Explorer hatt støtte for innfødt dra og slipp siden versjon 5.5; Faktisk er HTML5-implementeringen basert på IEs støtte. I dagens veiledning ser vi på hvordan du implementerer innfødt dra og slipp for å bygge en enkel handlekurvgrensesnitt.


Trinn 0. Hva vi gjør

Her er det vi skal bygge: det er en grunnleggende handlekurv med et produktpanel og et vognpanel. For å "kjøpe" et produkt, kan du dra det fra panelet til handlekurven; Vi holder oversikt over antall og fjerner elementer fra produktpanelet når de er ute av lager.

Merk at vi faktisk ikke bygger en handlekurv her; Vi vil ikke jobbe med server-side godhet i dag. Dette er bare fronten; poenget er HTML5 dra og slipp.


Trinn 1. HTML

Selvfølgelig begynner vi med HTML; her er vårt skall:

     Dra og slipp handlekurven        

Ganske grunnleggende: Vi knytter til et stilark og jQuery; Vi bruker bare jQuery for enkel hendelseshåndtering og DOM-manipulering; dra og slipp vil være innfødte. Vi står opp imot en vegg her, fordi HTML5 dra og slipp legger til noen egenskaper til hendelsesobjektet. JQuery bruker ikke standardhendelse objektet; det skaper sin egen for å utjevne hendelsesobjektproblemer. På grunn av dette får vi ikke de spesielle egenskapene med jQuery's eventobjekt. Men ikke bekymre deg; det er et plugin for det; Vi drar i Native Drag and Drop for å få alt til å fungere. Til slutt vil vi inkludere vårt skript: dragdrop.js.

Nå er vi klare til å legge til i produktlisten vår; For produktbilder bruker jeg ikoner fra Apple Icon Superpack, laget av SvenVath. (Jeg har omdøpt ikonene med enklere navn og endret dem til 180px.)

Legg til ul # produkter som det første barnet inne i kroppen. Når du har gjort det, undersøker vi det første listeelementet:

 
  • iMac

    Pris: $ 1199.00

    Mengde: 10

  • Vi har fått ut artikkelen, med et anker inni; Legg merke til at hvert ankerelement vil ha en klasse av punkt (viktig når vi kommer til CSS) og et egendefinert ID (viktig når vi kommer til JavaScript). Deretter har ankeret også flytt = "true" Egenskap; Dette burde være alt vi trenger for å gjøre elementet draggbart (vi får se noen advarsler snart). Vi bruker en anker-tag her, slik at du kan gjøre noe for nettlesere uten innfødt dra og slipp-støtte (selv om vi ikke gjør det her). Deretter har vi produktbildet og en div med produktinformasjonen. Og ja, det er nødvendig å pakke pris og mengde med span

    Her er resten av listepostene:

     
  • iPhone

    Pris: $ 199.00

    Mengde: 16

  • AppleTV

    Pris: $ 299.00

    Mengde: 9

  • Cinema Display

    Pris: $ 899.00

    Mengde: 4

  • iPod Nano

    Pris: $ 149.00

    Mengde: 20

  • Macbook

    Pris: $ 1199.00

    Mengde: 1. 3

  • Mac Mini

    Pris: $ 599.00

    Mengde: 18

  • Det er ett siste stykke HTML: handlekurven:

     

    Handlevogn

      Total: $0,00


      Drop her for å legge til i handlekurven

      Og det er vår HTML!


      Full Screencast



      Trinn 2. CSS

      Ideelt sett må alt du trenger å gjøre for å lage et element som kan trekkes er satt som dragerbart attributt til sant; Det er imidlertid mer til det. For å få ting til å fungere skikkelig, må du stille inn noen ting i CSS. Først tenk på dette: Hva klikker og drar gjør på "normalt" (undraggable) element? Vanligvis velger den tekst. Da vil vi sørge for at vi drar elementet, og ikke bare innholdet. For å håndtere, må du bruke følgende CSS:

       [draggable = true] -moz-user-select: none; -webkit-bruker-velg: ingen; -webkit-bruker-dra: element; 

      For enkelhets skyld bruker den innfødte dra og slipp-plugin-modulen oss disse egenskapene for oss, så vi kan legge dem ut hvis vi vil. Vi vil imidlertid gjøre dette:

       [draggable = true] cursor: move; 

      La oss begynne styling:

       html høyde: 100%;  kropp bakgrunn: #ececec; margin: 0; padding: 0; font: 13px / 1.5 helvetica, arial, san-serif; høyde: 100%;  h1, h2 text-align: center;  h2 posisjon: absolutt; bunn: 20px; farge: #fff; tekstskygge: 0 0 10px rgba (0, 0, 0, 0.75); display: none;  p margin: 0; 

      Siden vi ikke bruker full tilbakestilling, er det vår pseudo-tilbakestilling. Det skal alle være ganske selvforklarende. Vi setter høyden til 100% på html og kropp elementer fordi vi vil #cart å være hele høyden på skjermen; For å gjøre det, må hvert foreldreelement ha sin høyde satt til 100%. Vær også oppmerksom på at vi bruker rgba til å sette skyggenfarge Hvis en nettleser ikke støtter dette, vil det ikke være en skygge på h2. Og vi gjemmer dette h2 ved innstilling skjerm: ingen. Husk at h2 sier "Drop her for å legge til i handlekurven", så vi får det til å falme inn når draen starter og falmer ut når dragen slutter.

      Fortsett på vår produktliste ...

       #products float: left; list-style: none; bredde: 65%; padding: 0;  #products li display: inline; 

      Igjen, ganske opplagt. Det viktigste i denne utdrag er at listepostene vil bli vist inline. Siden vi setter inn display: block; float: left På ankrene vil IE gi listepostene en "trapp-trinn" -effekt; Vi kan jobbe rundt denne feilen ved å sette inn skjerm: inline på ankerets foreldreelement.

      Når vi snakker om ankrene, la oss stille dem neste.

       .element display: block; float: venstre; bredde: 180 piksler; høyde: 180 piksler; margin: 10px; border: 1px solid # 494949; tekst-Justering: center; text-decoration: none; farge: # 000; flow: hidden;  .item img border: 0; margin: 10px auto; bredde: 160 piksler; høyde: 160 piksler;  .item div bakgrunn: rgb (0, 0, 0); bakgrunn: rgba (0, 0, 0, 0,5); stilling: i forhold; bottom: 69px; color: # f3f3f3; polstring: 5px 0; display: none; 

      Hvert anker vil bli stylet som en 180x180px boks; Dette vil bli fylt med produktbildet. Produktinfo div vil bli plassert over bildet, nederst på torget. Legg merke til at vi må sette en bakgrunnsfarge og deretter tilbakestille den til moderne nettlesere, fordi IE ikke støtter RGBa. Vi setter inn display: none På denne info div så vi kan fade det inn og ut når "kunden" svinger på og av, henholdsvis.

      Alt som er igjen å style er handlekurven; vi vil se på det her, men husk, at listepostene vil bli satt inn av jQuery senere, så du vil ikke se dette på plass ennå.

       #cart float: right; background-color: #ccc; bredde: 25%; polstring: 0 5%; høyde: 100%;  #cart ul polstring: 0;  #cart li listestil: none; border-bottom: 1px solid # 494949; padding: 5 px;  #cart .quantity font-weight: bold; padding-right: 10px; margin-right: 10px; border-right: 1px solid # 494949; display: inline-blokk; bredde: 15px; tekst-Justering: høyre;  #cart .price float: right;  #total float: right; 

      Elementer med klassene mengde og pris vil være innenfor de dynamisk innsatte listepostene.

      Det er det for CSS; før vi går videre til stjernen i dette showet, la oss se på vårt arbeid så langt.



      Trinn 3. JavaScript

      Vi har gjort det til JavaScript; i henhold til HTML5-legen:

      HTML 5 DnD er basert på Microsofts originale implementering som var tilgjengelig så tidlig som Internet Explorer 5! Nå støttes for tiden i IE, Firefox 3.5 og Safari 4.

      Her er en liste over hendelsene som HTML5 dra og slipp tilbyr:

      • dra
      • dragstart
      • dragover
      • dragenter
      • dragleave
      • dragend
      • miste

      Vi vil ikke bruke alle disse, men vi får se hvordan de fleste jobber.

      Først skal vi jobbe med våre produkter:

       $ ('. item') .bind ('drastart', funksjon (evt) evt.dataTransfer.setData ('text', this.id); $ ('h2'). fadeIn ('fast');) .hover (funksjon () $ ('div', dette) .fadeIn ();, funksjon () $ ('div', dette) .fadeOut (););

      Vi begynner med å fange alle elementene; da binder vi en funciton til dragstart begivenhet; Denne hendelsen vil brenne når vi begynner å dra hendelsen. Det første vi skal gjøre når et objekt er trukket, er satt inn noen data; faktisk, hvis ingen data er angitt, vil firefox ikke la elementet trekke. Spesielle å dra hendelser er en objektegenskap på eventobjektet som heter data overføring; Vi bruker to metoder for denne eiendommen: setData og GetData. Her bruker vi setData metode, som tar to parametere: et dataformat og dataene. Vi bruker datatypen 'tekst'. Da vil vi sette dataene til å være ID for elementet brukeren drar. Da vil vi falme i h2 som et spørsmål til kunden.

      Vi bruker også jQuery-svingemetoden til å fade i produktinformasjonen når vi musiserer og fader det ut når vi musiserer. Legg merke til at vi passerer noden vi svinger over som kontekst, så vi får bare div av det aktuelle produktet.

      La oss nå legge til hendelseshåndteringene til #cart. Vi skal handle på dragover, dragenter, og miste arrangementer:

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

      For å få slipphendelsen til å brann, må vi avbryte standardhandlingen på dragover begivenhet; Denne hendelsen brenner kontinuerlig på drop-målet når et trekkbart element er trukket over det. For kun IE må vi avbryte standardhandlingen på dragenter hendelse, som bare skjer når det trekkbare elementet går inn i drop-målet. Årsakene til å avbryte standardhandlingen er noe tåkete; For å være ærlig forstår jeg ikke egentlig dem. Her er hva Remy Sharp sier om det:

      Det som forteller nettleseren er at dette elementet er det vi ønsker å fange dra hendelsen mot, ellers nettleseren går videre, er det normalt dra handling. Så ved å kansellere arrangementet, forteller det nettleseren at dette er elementet som skal begynne å bevege seg.

      Jeg burde merke at jQuery hjelper oss litt her, normalt må vi også returner falsk det får det til å fungere i IE; JQuery er imidlertid fast preventDefault gjør det for oss.

      miste begivenhet; Denne hendelsen blir også sparket på drop-målet, som er div # kurven i vårt tilfelle. Før vi ser på funksjonen, la oss snakke om hva denne funksjonen skal gjøre:

      • få produktet vi har tapt
      • Hvis produktet allerede er kjøpt, legg til en til det kjøpte kjøpet; Ellers legger du til varen i handlekurven
      • redusere produktmengden
      • oppdatere totalprisen

      Her er den første delen:

       var id = evt.dataTransfer.getData ('tekst'), element = $ ('#' + id), cartList = $ ("# cart ul"), totalt = $ ("# total spenning"), pris = $ ('p: eq (1) span', element) .text (), prevCartItem = null, ikkeInCart = (funksjon () var lis = $ ('li', kartliste), 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;

      Jeg vet; Det er mange variabler, men vi bruker dem alle. La oss gå over dem; Først får vi tekstdataene vi overførte med arrangementet; Vi overførte id slik som dette fordi det ikke er noe i hendelsesobjektet for å fortelle oss hvilket element som ble tapt på målet vårt; vi får ID og bruker det for å finne elementet som ble tapt. Deretter får vi vognlisten og totalprisen. Da får vi prisen på det enkelte elementet; Vi vet at det er spenningen i elementets andre ledd, så vi kan bruke elementet som kontekstparameter. Vi stiller inn prevCartItem til null for nå, men vi vil bruke det for å se om elementet som er trukket inn i handlekurven, allerede er der. Verdien av notInCart er en selvoppkallende anonym funksjon; det vil sløyfe over hvert liste element i kartlisten (igjen, vi bruker kontekstparameteren) og sjekke for å se om dataegenskapen id er det samme som variabelen id. For å forstå dette må du vite at når vi legger til listeobjekter i handlekurven, bruker vi jQuery data Metode for å angi butikkprodukt-ID med varen. I denne funksjonen ser vi etter en liste med de riktige dataene; hvis vi finner en, er varen allerede i handlekurven, og så setter vi inn notInCart til falsk; Hvis den ikke er i handlekurven, setter vi variabelen til ekte. Til slutt bruker vi quantLeftEl, quantBoughtEl, og quantLeft når du oppdaterer mengder.

      Nå, for noen tiltak:

       $ ( "H2") fadeout ( 'fort.'); hvis (ikkeInCart) prevCartItem = $ ('
    • ', tekst: $ (' p: først ', element) .text (), data: id: id)', ' klasse ':' kvantitet ', tekst:' 0 ')) prepend ($ ('', ' klasse ':' pris ', tekst: pris)) appendTo (kartliste);
    • Først vil vi fade ut h2 teksten. Så, hvis varen ikke er i handlekurven, legger vi den til handlekurven. For å gjøre dette, vil vi opprette en liste element; da kan vi passere et objekt bokstavelig som den andre parameteren for å angi egenskaper til vårt nye listepunkt. Vi stiller teksten til produktnavnet; som kommer fra første ledd i produktelementet. Da satte vi opp dataene vi snakket om ovenfor.

      Deretter forbereder vi et spann til dette listeposten; Vi gir den en klasse av 'kvantitet' (ikke glem å sette klassen i sitater, siden det er et reservert ord) og sett teksten til null; Ja, jeg vet at det burde være en, siden de bare har lagt varen i handlekurven, men vi vil øke det senere ... og du vil se hvorfor.

      Vi forbereder et annet spann til listen elementet, denne gangen for prisen. Vi skal flyte prisen til høyre, så det virker logisk å føyer den; men det ville føre til en float bug i IE; spenningen vil actaully flyte rett og under listen elementet.

      Til slutt legger vi til listeposten i handlekurvlisten.

      Det siste stykket av denne funksjonen vil kjøre om varen allerede er i handlekurven eller ikke:

       quantLeftEl = $ ('p: siste span', element); quantLeft = parseInt (quantLeftEl.text (), 10) - 1; quantLeftEl.text (quantLeft); quantBoughtEl = $ ('. quantity', prevCartItem); quantBoughtEl.text (parseInt (quantBoughtEl.text (), 10) + 1); hvis (quantLeft === 0) item.fadeOut ('fast'). fjern ();  total.text ((parseFloat (total.text (), 10) + parseFloat (price.split ('$') [1]). toFixed (2)); evt.stopPropagation (); returner falsk;

      Først får vi mengden fra produktelementet; Dette er mengden igjen når kunden trakk varen til handlekurven; vi får så mye som virkelig er igjen; men det er en streng, så vi bruker den innfødte funksjonen parseInt å konvertere det til et tall (bruk 10 som radix for å sikre at vi får et desimalnummer) og trekke en fra den. Da tilbakestiller vi kvantiteten ved hjelp av jQuery's tekst metode.

      Deretter får vi mengden brukeren har kjøpt; Dette er elementet med en klasse av 'kvantitet'; vi bruker prevCartItem som konteksten; dette fungerer fordi hvis varen allerede var i handlekurven, prevCartItem ble satt i den anonyme funksjonen; Hvis det ikke var i handlekurven, satte vi det når vi opprettet handlekurven. Vi kan da angi tekstverdien ved å få den nåværende verdien, konvertere til et nummer, og legge til en til den.

      Hva skjer når mengden igjen treffer null? Hvis det er null, forsvinner vi elementet og fjerner det.

      Til slutt må vi oppdatere totalprisen. Vi har det totale spekteret, så vi kan bare tilbakestille teksten. hva vi gjør er å få gjeldende tekst, konvertere den til et nummer (denne gangen bruker vi parseFloat å holde centene), splitte dollarskiltet av prisen og konvertere det til et tall og legge til to verdier. Til slutt bruker vi toFixed for å sørge for at vi alltid viser riktig cents verdi.

      Til slutt vil vi ikke ha miste slipp hendelsen til boble, så vi vil stoppe forplantningen og returnere falsk;


      Trinn 4. Det fullførte prosjektet

      God jobb, vi er ferdige; her er et skudd av handlekurven vår i gang:


      Hvis du vil sjekke ut hva de andre dra og slippe hendelsene gjør, legger du til dette i skriptet:

       $ ('# cart'). bind ('dragleave', funksjon (evt) console.log ('dragleave');); $ ('. item') .bind ('dra', funksjon (evt) console.log ('dragend');) .bind ('drastart', funksjon (evt) console.log ('drastart') ;) .bind ("dra", funksjon (evt) console.log ('dra'););

      Mens innfødt HTML5 dra og slipp, er kanskje ikke helt klart for prime tid ennå (Opera støtter ikke det), er det definitivt spennende å se hvor ting går!