Glisser-déposer de groupes d’éléments en JavaScript

Le glisser-déposer permet de déplacer plusieurs éléments de manière intuitive, notamment pour réorganiser des listes, déplacer des cartes entre des colonnes, organiser des fichiers ou modifier l’ordre de composants dans une interface. En JavaScript, cette interaction peut être implémentée soit avec l’API HTML5 native de glisser-déposer, soit avec des événements de souris permettant un contrôle plus précis du déplacement.

Pour gérer un groupe d’éléments, il faut distinguer l’élément ou les éléments déplacés, la zone de dépôt et les événements qui contrôlent le cycle complet : préparation du déplacement, déplacement, détection de la cible, dépôt et nettoyage. L’API native s’appuie notamment sur l’attribut draggable, l’objet DataTransfer et les événements dragstart, dragover, drop et dragend.

Principe du glisser-déposer en JavaScript

Drag’n’Drop est une excellente solution d’interface. Prendre quelque chose et le faire glisser est un moyen clair et simple de faire beaucoup de choses, de la copie et du déplacement de documents (comme dans les gestionnaires de fichiers) à la commande (déposer des articles dans un panier).

Drag & drop (ou glisser déposer) est une méthode qui permet de déplacer les éléments graphiques à l’aide de la souris, ou directement sur l’écran tactile (smartphone, tablette. ). Le système de drag and drop n’est pas propre qu’aux applications Web, mais a toujours été très célèbre sur les systèmes d’exploitation (principalement Windows et MacOS) depuis bien longtemps.

Dans une page Web, le système de drag and drop offre une interactivité évoluée avec l’utilisateur, surtout si celui-ci s’y rend à l’aide d’un appareil à écran tactile. C’est ce qui explique pourquoi de nombreux sites et applications Web le mettent en œuvre sur leurs pages comme c’est le cas sur Gmail où vous pouvez glisser un fichier depuis votre ordinateur afin de le joindre à un Email.

Dans la norme HTML moderne, il y a une section à propos du Drag and Drop avec des événements spéciaux tels que dragstart, dragend, etc. Ces événements nous permettent de prendre en charge des types spéciaux de glisser-déposer, tels que la gestion du glisser-déposer d’un fichier depuis le gestionnaire de fichiers du système d’exploitation et le déposer dans la fenêtre du navigateur.

Ensuite, JavaScript peut accéder au contenu de ces fichiers. L’API glisser-déposer native repose sur une série d’événements DOM et l’attribut global `draggable`.

API HTML5 native et groupes d’éléments

La version 5 de HTML a apporté beaucoup de nouveautés que j’ai résumées dans cette leçon consacrée à la présentation du standard HTML5. Parmi elles il y a la prise en charge de drag & drop à l’aide de l’attribut booléen draggable que l’on peut déclarer dans l’élément que l’on souhaite déplacer.

Bien entendu, c’est le Javascript qui va faire tout le travail. En effet, Javascript dispose d’une API avec une large collection d’événements, attributs et méthodes qui permettent de mettre en place un système de glisser-déposer, en l’occurence, la propriété dataTransfer qui contient toutes les informations concernant les éléments à déplacer.

Le choix de l’API HTML5 native par rapport aux bibliothèques externes offre plusieurs avantages techniques et architecturaux :

  • Standardisation et compatibilité des navigateurs : L’API est un standard web qui est nativement pris en charge par tous les navigateurs modernes, réduisant ainsi la nécessité d’utiliser des polyfills.
  • Rendement : Comme la fonctionnalité est implémentée nativement dans le navigateur, sa performance est généralement supérieure à celle des émulations basées sur JavaScript.
  • Accessibilité : L’implémentation native peut interagir mieux avec les technologies d’assistance, sous réserve que les attributs ARIA correspondants soient correctement définis.
  • Transfert de données (Data Transfer) : L’API offre un objet `DataTransfer` dédié qui permet de stocker et récupérer des données typées MIME (par exemple du texte, des URL ou des données personnalisées) pendant le processus de glisser-déposer.

L’interaction se divise en deux principaux domaines : l’élément source de glisser-déposer (Drag Source) et la cible d’accrochage (Drop Target). Le processus de glisser-déposer est contrôlé par une chaîne définie d’événements qui doivent être traités avec précision pour garantir la fonctionnalité souhaitée.

Cycle des événements de glisser-déposer

Le glisser-déplacer (drag-and-drop) en html5-javascript se programme en décomposant le traitement selon les étapes suivantes:

  • utilisation de la propriété draggable pour rendre des objets déplaçables
  • gestion des évènements de glisser-déposer du côté de la source (objet déplacé) dragstart drag dragend
  • gestion des évènements de glisser-déposer du côté de la cible (zone/objet recevant l’objet déplacé) dragenter dragleave dragover
  • gestion des types de déplacement (copie, déplacement (move), alias (lien)) et choix des données déplacées se fait par l’intermédiaire de l’objet dataTransfer accessible, par exemple, par event.dataTransfer ou event est l’argument d’une callback utilisée pour gérer les évènements de glisser-déposer

L’implémentation nécessite la surveillance et le contrôle au moins de six événements centraux. Le cœur de cette fonctionnalité est l’objet `DataTransfer`, accessible via les objets d’événement, servant de stockage temporaire pour les informations à déplacer.

Événement dragstart

Cet événement est déclenché dès que l'utilisateur commence à faire glisser un élément. Ici, les informations à transférer doivent être stockées dans l’objet `dataTransfer`, généralement via `event.dataTransfer.setData(format, data)`. Pour la réorganisation d'un menu, cela pourrait être l'ID de l'élément déplacé.

Cette fonction est déclenchée lorsqu’un utilisateur commence à glisser un élément. Il stocke l’élément traîné dans dragSrcEl, règle l’effet de traînée sur « déplacer », et stocke le contenu HTML de l’élément traîné dans l’objet dataTransfer.

Événement dragover

Cet événement est déclenché continuellement pendant que l’élément glissé est déplacé au-dessus d'un potentiel cible. Pour permettre le dépôt, la standard action du navigateur doit être explicitement supprimée, généralement par `event.preventDefault()`. Cela signale au navigateur que la zone est une cible de dépôt valide.

L’événement ondragover spécifie où les données glissées peuvent être déposées. Par défaut, les données/éléments ne peuvent pas être déposés dans d'autres éléments.

Pour permettre un drop, il faut empêcher la gestion par défaut de l’élément. Cela se fait en appelant la méthode event.preventDefault() pour l’événement ondragover.

Événement drop

Cet événement se produit lorsque l’élément est relâché avec succès sur le cible. Ici, les informations stockées lors du `dragstart` sont récupérées via `event.dataTransfer.getData(format)`. Ensuite, la manipulation réelle du DOM a lieu, par exemple le déplacement de l’élément menu vers une nouvelle position dans la liste.

Lorsque les données déplacées sont déposées, un événement de dépôt se produit. Dans l’exemple ci-dessus, l’attribut ondrop appelle une fonction, drop(event).

Appelez PreventDefault() pour empêcher le traitement par défaut des données par le navigateur (la valeur par défaut est ouverte sous forme de lien lors du dépôt). Récupérez les données déplacées avec la méthode dataTransfer.getData(). Cette méthode renverra toutes les données définies sur le même type dans la méthode setData(). Les données déplacées sont l’identifiant de l’élément déplacé ("drag1"). Ajouter l’élément glissé dans l’élément déposé.

Événement dragend

Cet événement est déclenché lorsque le processus de glisser-déposer est terminé, indépendamment du succès ou de l’annulation du dépôt. Il sert principalement à la nettoyage, comme le réinitialisation des états visuels ou l’élimination des classes temporaires.

Une fois le dragging terminé, cette fonction retire la classe de dragging de l’objet, la ramenant à son apparence normale.

Rendre plusieurs éléments déplaçables

Pour rendre un élément déplaçable, définissez l’attribut draggable sur true.

Voici un exemple de structure HTML qui fonctionne avec le code JavaScript :

  • Item 1
  • Item 2
  • Item 3
  • Item 4

L’attribut glissable : L’attribut glissable = « true » rend les éléments de la liste glissables. Ces éléments seront les éléments de liste que les utilisateurs pourront réordonner en les faisant glisser-déposer.

Exemple de liste triable

Créer une interface web interactive et conviviale implique souvent de permettre aux utilisateurs de manipuler directement les éléments de la page. L’une de ces interactions consiste à activer la fonction de glisser-déposer, qui peut être utilisée pour créer des listes triables.

Cette fonctionnalité est particulièrement utile dans les situations où l’ordre des éléments est important, comme dans les applications de gestion des tâches, les playlists ou les pages de paramètres.

document.addEventListener("DOMContentLoaded", function() { const items = document.querySelectorAll(".draggable"); let dragSrcEl = null; function handleDragStart(e) { dragSrcEl = this; e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/html", this.innerHTML); this.classList.add("dragging"); } function handleDragOver(e) { if (e.preventDefault) { e.preventDefault(); // Necessary to allow a drop } return false; } function handleDrop(e) { if (e.stopPropagation) { e.stopPropagation(); // Prevent the event from bubbling up } if (dragSrcEl !== this) { dragSrcEl.innerHTML = this.innerHTML; this.innerHTML = e.dataTransfer.getData("text/html"); } return false; } function handleDragEnd() { this.classList.remove("dragging"); } items.forEach(item => { item.addEventListener("dragstart", handleDragStart); item.addEventListener("dragover", handleDragOver); item.addEventListener("drop", handleDrop); item.addEventListener("dragend", handleDragEnd); });});

Le script commence par l’ajout d’un écouteur d’événements pour l’événement DOMContentLoaded, garantissant que tous les éléments DOM sont entièrement chargés avant l’exécution du script.

Sélection des objets glissables : const items = document.querySelectorAll(« .traînable »);: Cela sélectionne tous les éléments dont la classe peut glisser.

Ces éléments seront les éléments de liste que les utilisateurs pourront réordonner en les faisant glisser-déposer.

Démarrage de la traînée de maniabilité : handle de fonction DragStart(e): Cette fonction est déclenchée lorsqu’un utilisateur commence à glisser un élément.

Il stocke l’élément traîné dans dragSrcEl, règle l’effet de traînée sur « déplacer », et stocke le contenu HTML de l’élément traîné dans l’objet dataTransfer. L’objet traîné est également visualement distingué par l’ajout de la classe de traînage.

Résistance à la traînée : fonction handleDragOver(e): Cette fonction permet de laisser tomber l’élément traîné en appelant e.preventDefault(). Sans cela, l’événement de drop ne sera pas déclenché.

Chute de la tenue de route : fonction handleDrop(e): Lorsque l’objet traîné est déposé sur un autre objet, cette fonction est déclenchée.

Cela empêche l’événement de se faire apparaître et vérifie si l’objet sur lequel on lâche est différent de celui traîné. Si oui, il échange le contenu HTML de l’élément traîné avec la cible de drop, réordonnant ainsi la liste.

Auditeurs d’événements pour chaque élément : Le script boucle chaque élément glissable et ajoute des écouteurs d’événements pour les événements de démarrage, de glisser, de déposer et de dragend, en associant chacun à la fonction de gestionnaire correspondante.

Style visuel des éléments déplacés

Pour styliser les objets glissables, vous pouvez utiliser le CSS suivant :

.draggable { padding: 8px; margin: 4px; background-color: #f0f0f0; border: 1px solid #ccc; cursor: move;}.dragging { opacity: 0.5;}

Objets traînables (.traînable): Ces éléments sont stylisés avec un rembourrage, une marge, une couleur de fond claire et une bordure. La propriété curseur : déplacer modifie le curseur pour indiquer que l’objet peut être glissé.

État de traînée (.traînant): Lorsqu’un objet est traîné, il devient semi-transparent (opacité : 0,5), fournissant un indice visuel que l’objet est en mouvement.

Les utilisateurs peuvent cliquer et maintenir n’importe quel élément de la liste pour commencer à le glisser. Au fur et à mesure que l’élément est déplacé, il devient semi-transparent pour indiquer son état actif.

Lorsque l’élément est déposé sur un autre élément de la liste, leur contenu est échangé, réorganisant ainsi la liste. Le script gère tous les événements nécessaires (Démarrage du traîn, traîner, déposer, glisser) pour garantir une expérience de glisser-déposer fluide.

Déplacer des groupes d’éléments avec l’API native

Pour gérer un groupe, l’identifiant de l’élément déplacé peut être placé dans l’objet `dataTransfer`. La cible récupère ensuite cet identifiant lors de l’événement `drop` et peut déplacer l’élément dans le conteneur approprié.

function allowDrop(ev) { ev.preventDefault();}function drag(ev) { ev.dataTransfer.setData("text", ev.target.id);}function drop(ev) { ev.preventDefault(); var data = ev.dataTransfer.getData("text"); ev.target.appendChild(document.getElementById(data));}

Dans l’exemple ci-dessus, l’attribut ondragstart appelle une fonction, drag(event), qui spécifie les données à faire glisser. La méthode dataTransfer.setData() définit le type de données et la valeur des données déplacées.

Dans ce cas, le type de données est "text" et la valeur est l’identifiant de l’élément déplaçable ("drag1").

Le code permet ensuite de déplacer l’élément identifié dans une autre zone, en utilisant `appendChild` pour modifier la structure du document.

Déplacer plusieurs éléments comme un seul groupe

Lorsque plusieurs éléments doivent être déplacés ensemble, le principe consiste à conserver leurs identifiants ou leurs données dans `dataTransfer`, puis à les récupérer dans la cible. Le groupe peut être représenté par le contenu HTML des éléments ou par une liste d’identifiants.

La logique JavaScript après l’événement `drop` est responsable non seulement de mettre à jour le DOM, mais aussi d’aligner les structures de données sous-jacentes (par exemple un tableau ou une base de données) pour garantir la persistance de la nouvelle organisation.

Dans les applications où l’ordre des éléments est important, le déplacement visuel doit donc être accompagné de la mise à jour de la structure de données qui représente le groupe et sa position.

Limites des événements natifs

Mais les événements de drag natifs ont également des limites. Par exemple, nous ne pouvons pas empêcher de faire glisser depuis une certaine zone. Nous ne pouvons pas non plus faire de glisser “horizontal” ou “vertical” uniquement.

Et il existe de nombreuses autres tâches de glisser-déposer qui ne peuvent pas être effectuées en les utilisant. En outre, la prise en charge des appareils mobiles pour de tels événements est très faible.

Dans l’API native, le navigateur contrôle une partie du comportement du déplacement, de l’image fantôme et du transfert de données. Cette approche convient aux cas classiques, mais elle est moins adaptée lorsque le déplacement doit être contraint, personnalisé ou compatible avec des interactions de souris très spécifiques.

Implémenter le déplacement avec les événements de souris

Ici, nous verrons comment implémenter le glisser-déposer à l’aide d’événements de souris.

Sur mousedown - préparer l’élément pour le déplacement, si nécessaire (éventuellement en créer une copie, y ajouter une classe ou autre). Puis sur mousemove le déplacer en changeant left/top et position:absolute.

Sur mouseup - effectue toutes les actions liées à un Drag’n’Drop terminé. Ce sont les bases.

Plus tard, nous verrons comment utiliser d’autres fonctionnalités, telles que la mise en évidence des éléments sous-jacents actuels pendant que nous les glissons.

Algorithme général

  1. Préparer l’élément sur l’événement `mousedown`.
  2. Le placer en position absolue si nécessaire.
  3. Suivre le pointeur pendant `mousemove` sur le document.
  4. Détecter la cible située sous le pointeur.
  5. Finaliser le déplacement sur `mouseup`.
  6. Supprimer les gestionnaires d’événements temporaires.

Les composantes clés sont:

  • Flux d’événements : ball.mousedown → document.mousemove → ball.mouseup (annule l’évènement natif de ondragstart).
  • Au démarrage du glissement - capturer le changement initial du curseur relativement à l’élément: shiftX/shiftY et le garder durant le glissement.
  • Détecter les éléments pouvant recevoir l’action déposer sous le curseur en utilisant document.elementFromPoint.
  • A l’exécution de l’évènement mouseup nous pouvons finaliser le déposer: changer les données, déplacer les évènements.
  • Nous pouvons mettre en valeur les éléments que nous survolons.
  • Nous pouvons limiter le glissement sur une surface et selon une direction voulue.
  • Nous pouvons utiliser la délégation d’évènements avec mousedown/up.

Exemple de déplacement contrôlé à la souris

ball.onmousedown = function(event) { // (1) la préparer au déplacement : réglé en absolute et en haut par z-index ball.style.position = 'absolute'; ball.style.zIndex = 1000; // déplacez-le de tout parent actuel directement dans body // pour le placer par rapport à body document.body.append(ball); // Centrer la balle aux coordonnées (pageX, pageY) function moveAt(pageX, pageY) { ball.style.left = pageX - ball.offsetWidth / 2 + 'px'; ball.style.top = pageY - ball.offsetHeight / 2 + 'px'; } // déplacer notre balle en positionnement absolu sous le pointeur moveAt(event.pageX, event.pageY); function onMouseMove(event) { moveAt(event.pageX, event.pageY); } // (2) déplacer la balle sur le déplacement de la souris document.addEventListener('mousemove', onMouseMove); // (3) laisser tomber la balle, retirer les gestionnaires inutiles ball.onmouseup = function() { document.removeEventListener('mousemove', onMouseMove); ball.onmouseup = null; };};

Un aspect important est le suivi de l’évènement mousemove sur le document, pas sur la balle.

A première vue, il semblerait que la souris soit toujours sur la balle, et nous pouvons lui appliquer l’évènement mousemove. Mais si nous nous rappelons, l’évènement mousemove se déclenche souvent, mais pas sur chaque pixel.

Donc après un mouvement rapide, le curseur peut sauter de la balle pour aller quelque part au milieu du document (ou bien même hors de la fenêtre). Donc nous devons écouter le document pour le capturer.

Empêcher le glisser-déposer natif des images

Si nous exécutons le code, nous pouvons remarquer quelque chose d’étrange. Au début de l’action Glisser-Déposer, la balle est prise en “fourchette”: Nous commençons à faire glisser son “clone”.

C’est parce que le navigateur a son propre Glisser-Déposer pour les images et quelques autres éléments qui s’exécute automatiquement et entre en conflit avec le nôtre.

Pour le désactiver:

ball.ondragstart = function() { return false;};

Maintenant tout rentre dans l’ordre.

Conserver le point de prise initial

Dans les exemples ci-dessus la balle est toujours déplacée ainsi, de sorte à ce que son centre soit au-dessous du curseur:

ball.style.left = pageX - ball.offsetWidth / 2 + 'px';ball.style.top = pageY - ball.offsetHeight / 2 + 'px';

Pas mal, mais il y a un effet secondaire. Pour initier le Glissser-Deposer, nous pouvons appliquer un mousedown n’importe où sur la balle. Mais si nous le faisons sur le rebord, alors la balle “saute” soudainement pour être centrée sous le curseur.

Ce serait mieux si nous gardions le changement initial de l’élément relativement au curseur. Par exemple, si nous commençons le glissement par le rebord de la balle, alors le curseur doit rester sur le rebord pendant le déplacement.

Lorsqu’un visiteur appuye sur le bouton (mousedown) - nous pouvons garder en mémoire la distance du curseur au coin gauche en haut de la balle dans des variables shiftX/shiftY. Nous devons garder cette distance en faisant le glissement.

Pour obtenir ces changements nous pouvons soustraire les coordonnées:

let shiftX = event.clientX - ball.getBoundingClientRect().left;let shiftY = event.clientY - ball.getBoundingClientRect().top;

Ensuite pendant qu’on fait le glissement nous positionnons la balle sur le même changement relativement au curseur, ainsi:

ball.style.left = event.pageX - shiftX + 'px';ball.style.top = event.pageY - shiftY + 'px';

Code avec positionnement corrigé

ball.onmousedown = function(event) { let shiftX = event.clientX - ball.getBoundingClientRect().left; let shiftY = event.clientY - ball.getBoundingClientRect().top; ball.style.position = 'absolute'; ball.style.zIndex = 1000; document.body.append(ball); moveAt(event.pageX, event.pageY); function moveAt(pageX, pageY) { ball.style.left = pageX - shiftX + 'px'; ball.style.top = pageY - shiftY + 'px'; } function onMouseMove(event) { moveAt(event.pageX, event.pageY); } document.addEventListener('mousemove', onMouseMove); ball.onmouseup = function() { document.removeEventListener('mousemove', onMouseMove); ball.onmouseup = null; };};ball.ondragstart = function() { return false;};

La différence est particulièrement notable si nous faisons glisser la balle depuis son coin gauche. Dans l’exemple précèdent la balle “saute” sous le curseur. Maintenant il suit facilement le curseur à partir de sa position en cours.

Détecter les cibles de dépôt

Dans les exemples précédents la balle pouvait être déposée juste “n’importe où” pour qu’elle y soit. En réalité, nous prenons souvent un élément et le déposons sur un autre.

Par exemple, un fichier dans un dossier, ou autre chose. En d’autres termes, nous prenons un élément “déplaçable” et le déposons sur un élément ou l’on peut déposer un élément “déposable”.

Nous avons besoin de savoir :

  • où l’élément a été déposé à la fin du glisser-déposer - pour effectuer l’action correspondante, et, de préférence, connaitre l’élément droppable que nous déplaçons pour le mettre en surbrillance.

Pourquoi mouseover et mouseup ne suffisent pas

Quelle peut être la première idée ? Probablement pour définir des gestionnaires de mouseover/mouseup sur des droppables potentiels ?

Mais cela ne marche pas. Le problème est que, pendant que nous exécutons le déplacement, l’élément déplaçable est toujours sur les autres éléments.

Et les évènements de la souris ont lieu seulement sur l’élément, pas sur ceux se trouvant au-dessous de ce dernier.

Par exemple, ci-dessous deux éléments <div>, un en rouge au-dessus d’un autre en bleu (couvert complètement). Il n’y a aucun moyen de capturer un évènement sur celui en bleu, parce que le rouge se trouve au-dessus de celui-ci:

div { width: 50px; height: 50px; position: absolute; top: 0;}<div style="background:blue" onmouseover="alert(Ne marche jamais')"></div><div style="background:red" onmouseover="alert('sur le rouge!')"></div>

De la même manière avec l’élément déplaçable, la balle est toujours au-dessus des autres éléments, donc les évènements s’exécutent sur lui. Quel que soit les gestionnaires que l’on assigne aux éléments se trouvant en bas, ils ne vont pas fonctionner.

C’est pourquoi l’idée initiale de mettre les gestionnaires sur des potentiels objets déposables ne fonctionne pas en pratique. Ils ne vont pas démarrer.

Utiliser elementFromPoint

Il existe une méthode appelée document.elementFromPoint(clientX, clientY). Elle retourne l’élément le plus imbriqué sur les coordonnées données relatif à une fenêtre (ou bien null si les coordonnées données sont hors de la fenêtre).

S’il y a plusieurs éléments qui se chevauchent sur les mêmes coordonnées, le plus haut est renvoyé.

Nous pouvons l’utiliser dans n’importe lequel de nos gestionnaires d’événements à la souris pour détecter le droppable potentiel sous le pointeur, comme ceci :

ball.hidden = true;let elemBelow = document.elementFromPoint(event.clientX, event.clientY);ball.hidden = false;

Remarque: nous devons cacher la balle avant l’appel. Sinon, nous aurons généralement une balle sur ces coordonnées, car c’est l’élément supérieur sous le pointeur : elemBelow=ball.

Donc, nous le cachons et montrons immédiatement à nouveau. Nous pouvons utiliser ce code pour voir quel élément nous sommes entrain de “survoler” à n’importe quel moment.

Identifier la cible courante

Une version élaborée du code de onMouseMove pour trouver les éléments qui peuvent recevoir un “déposer”:

let currentDroppable = null;function onMouseMove(event) { moveAt(event.pageX, event.pageY); ball.hidden = true; let elemBelow = document.elementFromPoint( event.clientX, event.clientY ); ball.hidden = false; if (!elemBelow) return; let droppableBelow = elemBelow.closest('.droppable'); if (currentDroppable != droppableBelow) { if (currentDroppable) { leaveDroppable(currentDroppable); } currentDroppable = droppableBelow; if (currentDroppable) { enterDroppable(currentDroppable); } }}

Les événements de déplacement de souris peuvent se déclencher en dehors de la fenêtre (lorsque la balle est déplacée hors de l'écran). Si clientX/clientY sont en dehors de la fenêtre, alors elementFromPoint renvoie null.

Les objets potentiels pouvant recevoir les déposer sont étiquetés avec la classe "droppable" (peut être une autre logique). La méthode `closest('.droppable')` permet de retrouver une cible parente lorsque le pointeur se trouve sur un élément imbriqué dans la zone de dépôt.

Dans l’exemple ci-dessous quand la balle est glissée sur le camp du gardien de but, ce dernier est mis en valeur.

let currentDroppable = null;ball.onmousedown = function(event) { let shiftX = event.clientX - ball.getBoundingClientRect().left; let shiftY = event.clientY - ball.getBoundingClientRect().top; ball.style.position = 'absolute'; ball.style.zIndex = 1000; document.body.append(ball); moveAt(event.pageX, event.pageY); function moveAt(pageX, pageY) { ball.style.left = pageX - shiftX + 'px'; ball.style.top = pageY - shiftY + 'px'; } function onMouseMove(event) { moveAt(event.pageX, event.pageY); ball.hidden = true; let elemBelow = document.elementFromPoint( event.clientX, event.clientY ); ball.hidden = false; if (!elemBelow) return; let droppableBelow = elemBelow.closest('.droppable'); if (currentDroppable != droppableBelow) { if (currentDroppable) { leaveDroppable(currentDroppable); } currentDroppable = droppableBelow; if (currentDroppable) { enterDroppable(currentDroppable); } } } document.addEventListener('mousemove', onMouseMove); ball.onmouseup = function() { document.removeEventListener('mousemove', onMouseMove); ball.onmouseup = null; };};function enterDroppable(elem) { elem.style.background = 'pink';}function leaveDroppable(elem) { elem.style.background = '';}ball.ondragstart = function() { return false;};

Maintenant nous avons “l’objet cible” en cours, que nous survolons, dans une variable currentDroppable Durant tout le processus et nous pouvons l’utiliser pour mettre en valeur une chose ou faire une autre chose.

Finaliser le dépôt d’un groupe

A l’exécution de l’évènement mouseup nous pouvons finaliser le déposer: changer les données, déplacer les évènements.

Lorsque le groupe est relâché, la cible stockée dans `currentDroppable` permet d’appliquer l’action correspondante. Il peut s’agir de déplacer les éléments dans un conteneur, d’échanger leur position, de modifier leur état ou de mettre à jour une structure de données.

Si aucun élément déposables n’est détecté, le déplacement peut être annulé ou l’élément peut rester à sa dernière position, selon le comportement prévu par l’interface.

Délégation d’événements et grands groupes

Nous pouvons utiliser la délégation d’évènements avec mousedown/up. Un gestionnaire d’évènement sur une grande surface qui contrôle la propriété event.target peut gérer le Glisser-déposer pour des centaines d’éléments.

Cette approche évite d’ajouter des gestionnaires distincts à chaque élément lorsque le groupe est important ou lorsque les éléments sont ajoutés dynamiquement.

La cible peut être déterminée à partir de `event.target`, tandis que la classe, l’identifiant ou une autre information permet d’identifier l’élément à déplacer et la zone susceptible de recevoir le dépôt.

Cas d’utilisation des groupes d’éléments

  • Boards Kanban : Déplacer des cartes d’affaires entre différentes colonnes (changement d’état).
  • Gestionnaire de fichiers : Déplacer des fichiers ou des répertoires entre des dossiers.
  • Éditeurs configurateurs e-commerce : Organiser les composants de produits ou des éléments personnalisables.
  • Éditeurs de listes de lecture : Changer l’ordre de lecture des fichiers multimédias.

Cette fonctionnalité est particulièrement utile dans les applications où les utilisateurs doivent réorganiser les éléments, comme les gestionnaires de tâches, les playlists ou les tableaux de bord personnalisables.

Si un système de gestion de contenu (CMS) permet l’édition de l’ordre d’affichage, le glisser-déposer est utilisé pour manipuler visuellement l’ordre des éléments listés (points de menu).

TypeScript et maintenance du code

Lorsque vous travaillez avec des systèmes d'événements complexes tels que l'API glisser-déposer, TypeScript offre de nombreux avantages.

La typification correcte des objets événement (par exemple `DragEvent` au lieu du générique `Event`) garantit que les développeurs peuvent accéder directement à l’objet `dataTransfer`, sans risquer d’erreurs en temps réel.

Cela améliore la qualité du code et sa maintenabilité, surtout dans des projets plus importants basés sur Vanilla JavaScript.

Bibliothèques et implémentation personnalisée

Il existe des frameworks qui fondent leur architecture sur cela : DragZone, Droppable, Draggable et d’autres classes.

La plupart d’entre eux font des choses similaires à celles décrites au-dessus, donc cela devrait être facile pour vous de les comprendre maintenant.

Ou bien même déployer le vôtre, parce que vous savez déjà comment gérer le processus, et comme vous le voyez cela pourrait être plus flexible que d’adapter une solution tierce.

schéma cycle glisser-déposer JavaScript

8 méthodes javascript pour les tableaux à connaître absolument !

tags: #drag #groupe #element #js