Trageți „n” Drop cu evenimente de mouse

Drag’n’Drop este o soluție excelentă de interfață. A lua ceva, a-l trage și a-l plasa este o modalitate clară și simplă de a face multe lucruri, de la copierea și mutarea documentelor (ca în managerii de fișiere) până la comandare (aruncarea articolelor într-un coș). standard există o secțiune despre Drag and Drop cu evenimente speciale precum dragstart, dragend și așa mai departe.

Aceste evenimente ne permit să acceptăm tipuri speciale de drag’n’drop, cum ar fi gestionarea glisării unui fișier din managerul de fișiere al sistemului de operare și plasarea acestuia în fereastra browserului. Apoi, JavaScript poate accesa conținutul acestor fișiere.

Dar evenimentele de drag nativ au și ele limitări. De exemplu, nu putem împiedica glisarea dintr-o anumită zonă. De asemenea, nu putem face doar glisarea „orizontală” sau „verticală”. Și există multe alte sarcini drag’n’drop care nu pot fi realizate folosindu-le. De asemenea, suportul dispozitivelor mobile pentru astfel de evenimente este foarte slab.

Deci, aici vom vedea cum să implementăm Drag’n’Drop folosind evenimente de mouse.

Algoritmul Drag’n’Drop

Algoritmul de bază Drag’n’Drop arată astfel:

  1. Activat mousedown – pregătiți elementul pentru mișcare, dacă necesar (poate creați o clonă a acestuia, adăugați o clasă sau orice altceva).
  2. Apoi, pe mousemove mutați-l schimbând left/top cu position:absolute.
  3. La mouseup – efectuați toate acțiunile legate de finalizarea glisării ‘drop.

Acestea sunt elementele de bază. Mai târziu vom vedea cum să facem alte funcții, cum ar fi evidențierea elementelor actuale care stau la baza lor în timp ce le tragem peste ele.

Iată implementarea glisării unei mingi:

Dacă rulăm codul, putem observa ceva ciudat. La începutul glisării, mingea „se bifurcă”: începem să-i tragem „clona”.

Iată un exemplu în acțiune:

Încercați să glisați cu mouse-ul și veți vedea un astfel de comportament.

Acest lucru se datorează faptului că browserul are propriul suport de drag-drop pentru imagini și alte câteva elemente. Se execută automat și intră în conflict cu a noastră.

Pentru a o dezactiva:

Acum totul va fi în regulă.

În acțiune:

Un alt aspect important – urmărim mousemove pe document, nu pe ball. Din prima vedere poate părea că mouse-ul este întotdeauna deasupra mingii și putem pune mousemove pe el.

Dar, după cum ne amintim, mousemove se declanșează des, dar nu pentru fiecare pixel. Deci, după o mișcare rapidă, indicatorul poate sări de la minge undeva în mijlocul documentului (sau chiar în afara ferestrei).

Deci ar trebui să ascultăm pe document pentru a o prinde.

Poziționarea corectă

În exemplele de mai sus, mingea este întotdeauna mutată astfel încât centrul ei să fie sub pointer:

Nu este rău, dar există un efect secundar. Pentru a iniția drag’n’drop, putem mousedown oriunde pe minge. Dar dacă „o ia” de la margine, atunci mingea „sare” brusc pentru a deveni centrată sub indicatorul mouse-ului.

Ar fi mai bine dacă păstrăm schimbarea inițială a elementului față de indicator.

De exemplu, dacă începem să trageți de marginea mingii, atunci indicatorul ar trebui să rămână peste margine în timp ce trageți.

Să ne actualizăm algoritmul:

Codul final cu o poziționare mai bună:

În acțiune (în interiorul <iframe>) :

Diferența se observă mai ales dacă tragem mingea de colțul din dreapta jos. În exemplul anterior, mingea „sare” sub pointer. Acum urmărește fluent indicatorul din poziția actuală.

Țintele potențiale de scădere (droppables)

În exemplele anterioare, mingea ar putea să fie lăsat doar „oriunde” pentru a rămâne. În viața reală luăm de obicei un element și îl lăsăm pe altul. De exemplu, un „fișier” într-un „folder” sau altceva.

Vorbind abstract, luăm un element „glisabil” și îl lăsăm pe elementul „droppable”.

Noi trebuie să știți:

  • unde a fost scăpat elementul la sfârșitul Drag’n’Drop – pentru a efectua acțiunea corespunzătoare,
  • și, de preferință, să știm ce este Trageți peste, pentru a o evidenția.

Soluția este cam interesantă și puțin cam dificilă, așa că hai să o acoperim aici.

Ce poate fi prima idee? Probabil pentru a seta mouseover/mouseup handlers pe potențiale droppables?

Dar asta nu funcționează.

Problema este că, în timp ce suntem glisând, elementul glisabil este întotdeauna deasupra altor elemente.Și evenimentele mouse-ului se întâmplă numai pe elementul de sus, nu pe cele de sub acesta.

De exemplu, mai jos sunt două elemente <div>, roșu deasupra albastru una (acoperă complet). Nu există nicio modalitate de a prinde un eveniment pe cel albastru, deoarece roșu este deasupra:

La fel cu un element glisabil. Mingea este întotdeauna deasupra altor elemente, așa că se întâmplă evenimente pe ea. Indiferent de manevrele pe care le-am setat pe elemente inferioare, acestea nu vor funcționa.

De aceea ideea inițială de a pune handlerele pe potențiale droppables nu funcționează în practică. Nu vor rula.

Deci, ce să faci?

Există o metodă numită document.elementFromPoint(clientX, clientY). Returnează cel mai imbricat element pe coordonatele date relative la fereastră (sau null dacă coordonatele date sunt în afara ferestrei).

Îl putem folosi în gestionarii noștri de evenimente de la mouse pentru a detecta potențialul care poate fi scăpat sub pointer, astfel:

Rețineți: trebuie să ascundem mingea înainte de apel (*). În caz contrar, vom avea de obicei o minge pe aceste coordonate, deoarece este elementul de sus sub indicator: elemBelow=ball. Așa că o ascundem și o afișăm imediat din nou.

Putem folosi codul respectiv pentru a verifica ce element „zburăm” în orice moment. Și gestionăm picătura când se întâmplă.

Un cod extins de onMouseMove pentru a găsi elemente „dropable”:

În exemplul de mai jos, când mingea este trasă peste poarta de fotbal, obiectivul este evidențiat.

Acum avem actualul „drop target”, peste care zburăm, în variabila currentDroppable pe parcursul întregului proces și îl putem folosi pentru a evidenția sau orice alte lucruri.

Rezumat

Am considerat un algoritm de bază Drag’n’Drop.

Componentele cheie:

  1. Flux de evenimente: ball.mousedowndocument.mousemoveball.mouseup (nu uitați să anulați nativul ondragstart).
  2. La pornire prin tragere – amintiți-vă de schimbarea inițială a indicatorului în raport cu elementul: shiftX/shiftY și păstrați-l în timpul glisării.
  3. Detectați elementele care pot fi plasate und er pointer folosind document.elementFromPoint.

Putem pune multe pe această bază.

  • Pe mouseup putem finaliza intelectual picătura: schimbăm date, mutăm elemente.
  • Putem evidenția elementele pe care le zburăm.
  • Noi poate limita glisarea după o anumită zonă sau direcție.
  • Putem folosi delegarea evenimentelor pentru mousedown/up. Un handler de evenimente cu suprafață mare care verifică event.target poate gestiona Drag’n’Drop pentru sute de elemente.
  • Și așa mai departe.

Există cadre care construiesc arhitectură peste ea: DragZone, Droppable, Draggable și alte clase. Majoritatea fac lucruri similare cu cele descrise mai sus, deci ar trebui să fie ușor de înțeles acum. Sau rulați-vă propriul dvs., deoarece puteți vedea că este suficient de ușor de făcut, uneori mai ușor decât adaptarea unei soluții terță parte.

Write a Comment

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *