web-dev-qa-db-fra.com

Comment implémenter un div glisser-déposer à partir de zéro avec JavaScript?

Il doit s'agir d'une combinaison de CSS et de JavaScript. Les étapes à suivre devraient être:

  1. Faites-le au-dessus de tous les autres éléments (quelle propriété spécifier?)
  2. Attraper l'événement quand il est cliqué (quel événement écouter?)
  3. Déplacez le div lorsque la souris se déplace.

Mais quels sont les détails?

21
omg

La manière jQuery:

Découvrez les jQueryUI addons draggable et droppable .

Des centaines d'heures ont été investies dans le framework jQuery pour rendre les tâches compliquées comme celle-ci presque triviales. Profitez des efforts de l'équipe jQuery pour rendre la programmation d'applications cross-browser riche plus facile pour nous tous;)

Chuck Norris's Way:

Si vous insistez pour essayer cela avec du javascript brut. Vous aurez envie de faire quelques choses. Premièrement, définissez par programme tous les éléments déplaçables sur un positionnement relatif/absolu. Si vous cliquez sur un élément particulier, faites en sorte que ses valeurs en haut/à gauche dans CSS reflètent les modifications apportées par les axes x, y de la souris jusqu'à ce que le clic soit relâché. De plus, vous souhaiterez mettre à jour le z-index de chaque élément déplaçable lorsque vous cliquez dessus pour le mettre en vue.

Tutoriel: Comment faire glisser et déposer avec Javascript

28
Sampson
  1. le rendre absolu positionné, avec un z-index élevé.
  2. vérifier pour onmousedown de la div.
  3. utilisez les attributs mouseX et mouseY de l'événement pour déplacer le div.

Voici un exemple de Javascript, le guide définitif (mis à jour ici ):

/**
 *  Drag.js:    drag absolutely positioned HTML elements.
 *
 *  This module defines a single drag() function that is designed to be called
 *  from an onmousedown event handler. Subsequent mousemove event will
 *  move the specified element. A mouseup event will terminate the drag.
 *  If the element is dragged off the screen, the window does not scroll.
 *  This implementation works with both the DOM Level 2 event model and the
 *  IE event model.
 *
 *  Arguments:
 *
 *      elementToDrag: the element that received the mousedown event or
 *          some containing element. It must be absolutely positioned. Its
 *          style.left and style.top values will be changed based on the user's
 *          drag.
 *
 *      event: ethe Event object for the mousedown event.
 *
 *  Example of how this can be used:
 *      <script src="Drag.js"></script> <!-- Include the Drag.js script -->
 *      <!-- Define the element to be dragged -->
 *      <div style="postion:absolute; left:100px; top:100px; width:250px;
 *                  background-color: white; border: solid black;">
 *      <!-- Define the "handler" to drag it with. Note the onmousedown attribute. -->
 *      <div style="background-color: gray; border-bottom: dotted black;
 *                  padding: 3px; font-family: sans-serif; font-weight: bold;"
 *          onmousedown="drag(this.parentNode, event);">
 *      Drag Me <!-- The content of the "titlebar" -->
 *      </div>
 *      <!-- Content of the draggable element -->
 *      <p>This is a test. Testing, testing, testing.<p>This is a test.<p>Test.
 *      </div>
 *
 *  Author: David Flanagan; Javascript: The Definitive Guide (O'Reilly)
 *  Page: 422
 **/
 function drag(elementToDrag, event)
 {
     // The mouse position (in window coordinates)
     // at which the drag begins
     var startX = event.clientX, startY = event.clientY;

     // The original position (in document coordinates) of the
     // element that is going to be dragged. Since elementToDrag is
     // absolutely positioned, we assume that its offsetParent is the
     //document bodt.
     var origX = elementToDrag.offsetLeft , origY = elementToDrag.offsetTop;

     // Even though the coordinates are computed in different
     // coordinate systems, we can still compute the difference between them
     // and use it in the moveHandler() function. This works because
     // the scrollbar positoin never changes during the drag.
     var deltaX = startX - origX, deltaY = startY - origY;

     // Register the event handlers that will respond to the mousemove events
     // and the mouseup event that follow this mousedown event.
     if (document.addEventListener) //DOM Level 2 event model
     {
         // Register capturing event handlers
         document.addEventListener("mousemove", moveHandler, true);
         document.addEventListener("mouseup", upHandler, true);
     }
     else if (document.attachEvent) //IE 5+ Event Model
     {
         //In the IE event model, we capture events by calling
         //setCapture() on the element to capture them.
         elementToDrag.setCapture();
         elementToDrag.attachEvent("onmousemove", moveHandler);
         elementToDrag.attachEvent("onmouseup", upHandler);
         // Treat loss of mouse capture as a mouseup event.
         elementToDrag.attachEvent("onclosecapture", upHandler);
     }
     else //IE 4 Event Model
     {
         // In IE 4, we can't use attachEvent() or setCapture(), so we set
         // event handlers directly on the document object and hope that the
         // mouse event we need will bubble up.
         var oldmovehandler = document.onmousemove; //used by upHandler()
         var olduphandler = document.onmouseup;
         document.onmousemove = moveHandler;
         document.onmouseup = upHandler;
     }

     // We've handled this event. Don't let anybody else see it.
     if (event.stopPropagation) event.stopPropagation();    //  DOM Level 2
     else event.cancelBubble = true;                        //  IE

     // Now prevent any default action.
     if (event.preventDefault) event.preventDefault();      //  DOM Level 2
     else event.returnValue = false;                        //  IE

     /**
      * This is the handler that captures mousemove events when an element
      * is being dragged. It is responsible for moving the element.
      **/
      function moveHandler(e)
      {
          if (!e) e = window.event; //  IE Event Model

          // Move the element to the current mouse position, adjusted as
          // necessary by the offset of the initial mouse-click.
          elementToDrag.style.left = (e.clientX - deltaX) + "px";
          elementToDrag.style.top = (e.clientY - deltaY) + "px";

          // And don't let anyone else see this event.
          if (e.stopPropagation) e.stopPropagation();       // DOM Level 2
          else e.cancelBubble = true;                       // IE
      }

      /**
       * This is the handler that captures the final mouseup event that
       * occurs at the end of a drag.
       **/
       function upHandler(e)
       {
           if (!e) e = window.event;    //IE Event Model

           // Unregister the capturing event handlers.
           if (document.removeEventListener) // DOM event model
            {
                document.removeEventListener("mouseup", upHandler, true);
                document.removeEventListener("mousemove", moveHandler, true);
            }
            else if (document.detachEvent)  //  IE 5+ Event Model
            {
                elementToDrag.detachEvent("onlosecapture", upHandler);
                elementToDrag.detachEvent("onmouseup", upHandler);
                elementToDrag.detachEvent("onmousemove", moveHandler);
                elementToDrag.releaseCapture();
            }
            else    //IE 4 Event Model
            {
                //Restore the original handlers, if any
                document.onmouseup = olduphandler;
                document.onmousemove = oldmovehandler;
            }

            //  And don't let the event propagate any further.
            if (e.stopPropagation) e.stopPropagation(); //DOM Level 2
            else e.cancelBubble = true;                 //IE
       }
 }

 function closeMe(elementToClose)
 {
     elementToClose.innerHTML = '';
     elementToClose.style.display = 'none';
 }

 function minimizeMe(elementToMin, maxElement)
 {
     elementToMin.style.display = 'none';
 }
14
Zack Marrapese

Drag and Drop HTML5

Si vous lisez ceci en 2017 ou plus tard, vous voudrez peut-être jeter un œil à l'API HTML5 Drag and Drop:

https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API

Exemple:

<!DOCTYPE HTML>
<html>
<head>
    <script>
    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));
    }
    </script>
    <style>
        .draggable {
            border: 1px solid black;
            width: 30px;
            height: 20px;
            float: left;
            margin-right: 5px;
        }
        #target {
            border: 1px solid black;
            width: 150px;
            height: 100px;
            padding: 5px;
        }
    </style>
</head>
<body>

    <h1>Drag and Drop</h1>

    <h2>Target</h2>
    <div id="target" ondrop="drop(event)" ondragover="allowDrop(event)"></div>

    <h2>Draggable Elements</h2>
    <div id="draggable1" class="draggable" draggable="true" ondragstart="drag(event)"></div>
    <div id="draggable2" class="draggable" draggable="true" ondragstart="drag(event)"></div>
    <div id="draggable3" class="draggable" draggable="true" ondragstart="drag(event)"></div>

</body>
</html>
5
maechler

L'API standard Drag and Drop est largement reconnue pour sucer de grosses boules d'âne poilues . Je ne recommanderais donc pas de le faire à partir de zéro. Mais puisque c'est votre question, il y a un ensemble d'exigences pour rendre quelque chose déplaçable et un ensemble d'exigences pour configurer correctement une zone de dépôt:

Glisser:

  • Le nœud dom doit avoir la propriété "draggable" définie sur true

Remarque: e.dataTransfer.setDragImage peut être utilisé pour définir une autre image de glissement (la valeur par défaut est une image transparente du nœud dom déplacé.

Note 2: e.dataTransfer.setData peut être utilisé à l'intérieur de l'événement dragstart pour définir certaines données qui peuvent être récupérées à partir de l'événement drop.

Goutte:

  • Dans l'événement dragover, e.preventDefault doit être appelé
  • Dans l'événement drop, e.preventDefault doit être appelé

Exemple:

<body>
    <div id="dragme" draggable="true">Drag Me</div>
    <div id="dropzone">Drop Here</div>
</body>

<script>
    var dragme = document.getElementById('dragme')
    var dropzone = document.getElementById('dropzone')

    dragme.addEventListener('dragstart',function(e){
        dropzone.innerHTML = "drop here"
    })

    dropzone.addEventListener('dragover',function(e){
        e.preventDefault()
    })
    dropzone.addEventListener('drop',function(e){
        e.preventDefault()
        dropzone.innerHTML = "dropped"
    })
</script>

Cependant, il existe de nombreux pièges dans l'utilisation de cette API, notamment:

  • il faut beaucoup de travail pour faire la distinction entre un événement dragmove sur une zone de dépôt et un événement dragmove lié à un élément déplaçable
  • dragmove se déclenche même si votre souris ne bouge pas
  • dragleave et dragenter se déclenchent même si votre souris ne se déplace pas dans ou hors du noeud dom d'écoute (elle se déclenche chaque fois qu'elle traverse un rebond enfant-parent pour une raison stupide)
  • Et plus..

Une meilleure façon

J'ai écrit une bibliothèque de glisser-déposer qui facilite considérablement l'utilisation de l'API de glisser-déposer standard sans tous ces pièges. Vérifiez le ici:

https://github.com/fresheneesz/drip-drop

3
B T

Oui, vous pouvez utiliser jQuery si vous voulez une bibliothèque gonflée avec bien plus de fonctions que vous n'en avez besoin! Ou si vous voulez être plus élitiste, utilisez bibliothèque de glisser-déposer de Waltern Zorn , qui est un dixième de la taille.

2
Josh Stodola
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));
}
.mydiv {
    float: left;
    width: 100px;
    height: 35px;
    margin: 10px;
    padding: 10px;
    border: 1px solid black;
}
<!DOCTYPE HTML>
<html>
<head>


</head>
<body>

<h2>Drag and Drop</h2>


<div id="div1" class="mydiv" ondrop="drop(event)" ondragover="allowDrop(event)">
  <img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a" draggable="true" ondragstart="drag(event)" id="drag1" width="88" height="31">
</div>

<div id="div2" class="mydiv" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<div id="div3" class="mydiv" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<div id="div4" class="mydiv" ondrop="drop(event)" ondragover="allowDrop(event)"></div>

</body>
</html>
2
Waruna Manjula
  1. Pour amener le div au-dessus d'autres éléments, vous devez lui attribuer un indice z élevé. En outre, vous pouvez définir une zone d'ombre pour indiquer à l'utilisateur que l'élément est déplaçable.
  2. Vous devez écouter un total de trois événements: mousedown, = mouseup, et mousemove. On mousedown vous devez attacher un écouteur sur mousemove , qui suit les mouvements du pointeur de la souris et déplace le div en conséquence, et sur mouseup vous devez supprimer l'auditeur sur mousemove.
  3. Déplacer le div avec la souris est un peu délicat. Si vous translate le div à la position du pointeur, le pointeur pointera toujours vers le coin supérieur gauche du div , même lorsque vous cliquez dans le coin inférieur droit. Pour cela, vous devez calculer la différence de coordonnées entre le div (coin supérieur gauche) et le pointeur de la souris, dans le mousedown gestionnaire d'événements. Ensuite, vous devez soustraire cette différence de la position de la souris avant de traduire le div à cette position, dans le mousemove gestionnaire d'événements.

Voir la démo pour une meilleure idée.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=Edge" />
    <title>Document</title>
    <style>
      body,
      html {
        width: 100%;
        height: 100%;
        padding: 0px;
        margin: 0px;
      }
      #box {
        width: 100px;
        height: 100px;
        margin: auto;
        background-color: lightblue;
      }
      #box:active {
        border: 1px solid black;
        box-shadow: 2px 2px 5px 5px #bbb6b6;
      }
    </style>
  </head>
  <body>
    <div id="box"></div>
  </body>
  <script>
    var box = document.getElementById("box");
    var diff = {};
    var getBoxPos = function() {
      return {
        x: box.getBoundingClientRect().x,
        y: box.getBoundingClientRect().y
      };
    };
    var calcDiff = function(x, y) {
      var boxPos = getBoxPos();
      diff = {
        x: x - boxPos.x,
        y: y - boxPos.y
      };
    };
    var handleMouseMove = function(event) {
      var x = event.x;
      var y = event.y;
      x -= diff.x;
      y -= diff.y;

      console.log("X " + x + " Y " + y);
      box.style.position = "absolute";
      box.style.transform = "translate(" + x + "px ," + y + "px)";
    };

    box.addEventListener("mousedown", function(e) {
      calcDiff(e.x, e.y);
      box.addEventListener("mousemove", handleMouseMove, true);
    });

    box.addEventListener("mouseup", function(e) {
      console.log("onmouseup");
      box.removeEventListener("mousemove", handleMouseMove, true);
    });
  </script>
</html>
1
Shahrukh Haider