Drag «n» Drop with mouse events

Drag’n’Drop er en flott grensesnittløsning. Å ta noe og dra og slippe det er en klar og enkel måte å gjøre mange ting på, fra å kopiere og flytte dokumenter (som i filbehandlere) til å bestille (slippe varer i en handlevogn).

I den moderne HTML standard er det et avsnitt om dra og slipp med spesielle hendelser som dragstart, dragend, og så videre.

Disse hendelsene lar oss støtte spesielle typer drag’n’drop, for eksempel håndtering av å dra en fil fra OS-filbehandling og slippe den i nettleservinduet. Da kan JavaScript få tilgang til innholdet i slike filer.

Men native Drag Events har også begrensninger. For eksempel kan vi ikke forhindre at vi drar fra et bestemt område. Vi kan heller ikke bare gjøre dragingen «horisontal» eller «vertikal». Og det er mange andre drag’n’drop-oppgaver som ikke kan gjøres ved å bruke dem. Også mobilenhetsstøtte for slike hendelser er veldig svak.

Så her får vi se hvordan du implementerer Drag’n’Drop ved hjelp av mushendelser.

Drag’n’Drop-algoritme

Den grunnleggende Drag’n’Drop-algoritmen ser slik ut:

  1. mousedown – forbered elementet for flytting, hvis nødvendig (kanskje opprett en klon av den, legg til en klasse i den eller hva som helst).
  2. Så på mousemove flytt den ved å endre left/top med position:absolute.
  3. mouseup – utfør alle handlinger relatert til å fullføre drag’n ‘drop.

Dette er det grunnleggende. Senere får vi se hvordan du kan gjøre andre funksjoner, for eksempel å fremheve nåværende underliggende elementer mens vi drar over dem.

Her er implementeringen av å dra en ball:

Hvis vi kjører koden, vi kan merke noe rart. På begynnelsen av drag’n’drop, «gafler» ballen: vi begynner å dra «klonen».

Her er et eksempel i aksjon:

Prøv å dra og dra med musen, så ser du en slik oppførsel.

Det er fordi nettleseren har sin egen drag’n’drop-støtte for bilder og noen andre elementer. Den kjører automatisk og kommer i konflikt med vår.

For å deaktivere den:

Nå vil alt være i orden.

I aksjon:

Et annet viktig aspekt – vi sporer mousemovedocument, ikke på ball. Fra første øyekast kan det se ut som at musen alltid er over ballen, og vi kan sette mousemove på den.

Men som vi husker, mousemove utløser ofte, men ikke for hver piksel. Så etter rask bevegelse kan pekeren hoppe fra ballen et sted midt i dokumentet (eller til og med utenfor vinduet).

Så vi bør lytte på document for å fange den.

Riktig posisjonering

I eksemplene ovenfor flyttes ballen alltid slik at den er midt under pekeren:

Ikke dårlig, men det er en bivirkning. For å initiere drag’n’drop kan vi mousedown hvor som helst på ballen. Men hvis «tar» det fra kanten, så «hopper» ballen for å bli sentrert under musepekeren.

Det ville være bedre hvis vi beholder elementets første skift i forhold til pekeren.

Hvis vi for eksempel begynner å dra ved kanten av ballen, bør pekeren forbli over kanten mens du drar.

La oss oppdatere algoritmen vår:

Den endelige koden med bedre posisjonering:

I aksjon (inne i <iframe>) :

Forskjellen er spesielt merkbar hvis vi drar ballen i høyre hjørne. I det forrige eksemplet «hopper» ballen under pekeren. Nå følger den pekeren flytende fra gjeldende posisjon.

Potensielle fallmål (droppable)

I tidligere eksempler kunne ballen bli droppet bare «hvor som helst» for å bli. I det virkelige liv tar vi vanligvis ett element og slipper det på et annet. For eksempel en «fil» i en «mappe» eller noe annet.

Når vi snakker abstrakt, tar vi et «drabart» element og slipper det på «droppable» -element.

Vi trenger å vite:

  • hvor elementet ble droppet på slutten av Drag’n’Drop – for å utføre den tilsvarende handlingen,
  • og helst kjenne den droppbare vi drar for å markere det.

Løsningen er ganske interessant og bare litt vanskelig, så la oss dekke den her.

Hva kan være den første ideen? Sannsynligvis for å sette mouseover/mouseup håndterere på potensielle droppables?

Men det fungerer ikke.

Problemet er at mens vi er å dra, er det drabare elementet alltid over andre elementer.Og mushendelser skjer bare på toppelementet, ikke på de under det.

For eksempel er nedenfor to <div> -elementer, rød på toppen av det blå en (helt dekker). Det er ingen måte å fange en hendelse på den blå, fordi den røde er på toppen:

Det samme med et dragbart element. Ballen er alltid på toppen av andre elementer, så hendelser skjer på den. Uansett hvilken håndterer vi setter på lavere elementer, vil de ikke fungere.

Derfor fungerer ikke den første ideen om å sette håndterere på potensielle droppables i praksis. De kjører ikke.

Så hva skal jeg gjøre?

Det er en metode som heter document.elementFromPoint(clientX, clientY). Den returnerer det mest nestede elementet på gitte vindusrelaterte koordinater (eller null hvis gitte koordinater er utenfor vinduet).

Vi kan bruke det i hvilken som helst av musebehandlerne våre for å oppdage potensialet som kan slippes under pekeren, slik:

Merk: vi må skjule ballen før samtalen (*). Ellers har vi vanligvis en ball på disse koordinatene, da det er toppelementet under pekeren: elemBelow=ball. Så vi skjuler det og viser umiddelbart igjen.

Vi kan bruke den koden til å sjekke hvilket element vi «flyr over» når som helst. Og håndtere slipp når det skjer.

En utvidet kode på onMouseMove for å finne «droppbare» elementer:

I eksemplet nedenfor når ballen blir dratt over fotballmålet, blir målet markert.

Nå har vi det nåværende «slippmålet», som vi flyr over, i variabelen currentDroppable under hele prosessen, og kan bruke den til å markere eller andre ting.

Sammendrag

Vi betraktet en grunnleggende Drag’n’Drop-algoritme.

Nøkkelkomponentene:

  1. Hendelsesflyt: ball.mousedowndocument.mousemoveball.mouseup (ikke glem å avbryte native ondragstart).
  2. Ved dra-start – husk den første forskyvningen av pekeren i forhold til elementet: shiftX/shiftY og hold den mens du drar.
  3. Oppdag droppbare elementer und er pekeren ved hjelp av document.elementFromPoint.

Vi kan legge mye på dette fundamentet.

  • mouseup vi kan intellektuelt fullføre dråpen: endre data, flytte elementer rundt.
  • Vi kan markere elementene vi flyr over.
  • Vi kan begrense dra etter et bestemt område eller retning.
  • Vi kan bruke hendelsesdelegering for mousedown/up. En hendelsesbehandler for store områder som sjekker event.target, kan administrere Drag’n’Drop for hundrevis av elementer.
  • Og så videre.

Det er rammer som bygger arkitektur over den: DragZone, Droppable, Draggable og andre klasser. De fleste av dem gjør lignende ting som det som er beskrevet ovenfor, så det skal være lett å forstå dem nå. Eller rull deg selv, for du kan se at det er enkelt nok å gjøre, noen ganger lettere enn å tilpasse en tredjepartsløsning.

Write a Comment

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *