web-dev-qa-db-fra.com

Faites glisser et déposez HTML5 n'importe où sur l'écran

J'ai un journal de débogage que j'ai écrit en JavaScript pour un projet sur lequel je travaille. Le journal est essentiellement un <aside> tag en HTML5 qui ne s'affiche qu'en cas de besoin. Je voulais jouer avec l'idée de pouvoir déplacer le journal sur l'écran, car il peut chevaucher certaines choses (ce qui est bien pour mon projet). Cependant, je n'arrive pas à comprendre comment utiliser HTML5 pour glisser-déposer correctement la balise afin qu'elle puisse être placée n'importe où sur l'écran (enfin, ou dans un <div> élément).

Après avoir lu sur la prise en charge du glisser-déposer de HTML5, j'ai une compréhension de base de son fonctionnement, mais je ne sais pas par où commencer quand il s'agit de permettre au div d'être placé n'importe où (son z-index est une valeur élevée, donc comme je l'ai dit, le chevauchement est très bien).

Aucune suggestion?

Oh, et j'aimerais essayer d'éviter d'utiliser des bibliothèques externes pour ce projet, dans la mesure du possible. J'essaie de le faire en pur JavaScript/HTML5.

38
clicheName

Le glisser-déplacer ne déplace pas les éléments, si vous souhaitez que l'élément se déplace lorsque vous le déposez, vous devez définir la nouvelle position de l'élément dans l'événement de dépôt. J'ai fait un exemple qui fonctionne dans Firefox et Chrome, voici les points clés:

function drag_start(event) {
    var style = window.getComputedStyle(event.target, null);
    event.dataTransfer.setData("text/plain",
    (parseInt(style.getPropertyValue("left"),10) - event.clientX) + ',' + (parseInt(style.getPropertyValue("top"),10) - event.clientY));
} 

L'événement dragstart calcule le décalage du pointeur de la souris à partir de la gauche et du haut de l'élément et le passe dans le dataTransfer. Je ne m'inquiète pas de transmettre l'ID, car il n'y a qu'un seul élément déplaçable sur la page - pas de liens ou d'images - si vous avez quelque chose sur votre page, vous devrez faire un peu plus de travail ici.

function drop(event) {
    var offset = event.dataTransfer.getData("text/plain").split(',');
    var dm = document.getElementById('dragme');
    dm.style.left = (event.clientX + parseInt(offset[0],10)) + 'px';
    dm.style.top = (event.clientY + parseInt(offset[1],10)) + 'px';
    event.preventDefault();
    return false;
}

L'événement drop décompresse les décalages et les utilise pour positionner l'élément par rapport au pointeur de la souris.

L'événement dragover a juste besoin de preventDefault lorsque quelque chose est glissé. Encore une fois, s'il y a autre chose que vous pouvez faire glisser sur la page, vous devrez peut-être faire quelque chose de plus complexe ici:

function drag_over(event) {
    event.preventDefault();
    return false;
} 

Liez-le donc au document.body avec l'événement drop pour tout capturer:

var dm = document.getElementById('dragme');
dm.addEventListener('dragstart',drag_start,false);
document.body.addEventListener('dragover',drag_over,false);
document.body.addEventListener('drop',drop,false); 

Si vous souhaitez que cela fonctionne dans IE, vous devrez convertir l'élément aside en un élément a et, bien sûr, tout le code de liaison d'événement sera différent. L'API glisser-déposer ne fonctionne pas dans Opera, ni sur aucun navigateur mobile pour autant que je sache. De plus, je sais que vous avez dit que vous ne vouliez pas utiliser jQuery, mais la liaison d'événements entre navigateurs et la manipulation des positions des éléments est le genre de choses que jQuery facilite beaucoup.

104
robertc

J'ai ajusté un peu la grande réponse de robertc pour les cas de plusieurs éléments. Ici, le nom secondclass est juste pour une autre position.

<aside draggable="true" class="dragme" data-item="0">One</aside>
<aside draggable="true" class="dragme second" data-item="1">Two</aside>

Ajoutez l'attribut d'élément de données à la fonction setData.

function drag_start(event) {
  var style = window.getComputedStyle(event.target, null);
  event.dataTransfer.setData("text/plain", (parseInt(style.getPropertyValue("left"), 10) - event.clientX) + ',' + (parseInt(style.getPropertyValue("top"), 10) - event.clientY) + ',' + event.target.getAttribute('data-item'));
}

Ciblez l'élément qui est déplacé.

function drop(event) {
  var offset = event.dataTransfer.getData("text/plain").split(',');
  var dm = document.getElementsByClassName('dragme');
  dm[parseInt(offset[2])].style.left = (event.clientX + parseInt(offset[0], 10)) + 'px';
  dm[parseInt(offset[2])].style.top = (event.clientY + parseInt(offset[1], 10)) + 'px';
  event.preventDefault();
  return false;
}

Et parcourez tous les éléments avec une classe dragme.

var dm = document.getElementsByClassName('dragme');
for (var i = 0; i < dm.length; i++) {
  dm[i].addEventListener('dragstart', drag_start, false);
  document.body.addEventListener('dragover', drag_over, false);
  document.body.addEventListener('drop', drop, false);
}

stylo

6
Ingvi

Merci pour votre réponse. Cela fonctionne très bien dans Chrome et Firefox. Je l'ai modifié pour fonctionner dans IE. Ci-dessous est le code.

 <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="generator" content="CoffeeCup HTML Editor (www.coffeecup.com)">
        <meta name="dcterms.created" content="Fri, 27 Jun 2014 21:02:23 GMT">
        <meta name="description" content="">
        <meta name="keywords" content="">
        <title></title>
        
        <!--[if IE]>
        <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
        <style>
        li
        { 
          position:  absolute;
          left: 0;
          top: 0; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
          width: 200px; 
          background: rgba(255,255,255,0.66); 
          border: 2px  solid rgba(0,0,0,0.5); 
          border-radius: 4px; padding: 8px;
        }
        </style>
        <script>
            function drag_start(event) {
                var style = window.getComputedStyle(event.target, null);
                var str = (parseInt(style.getPropertyValue("left")) - event.clientX) + ',' + (parseInt(style.getPropertyValue("top")) - event.clientY) + ',' + event.target.id;
                event.dataTransfer.setData("Text", str);
            }

            function drop(event) {
                var offset = event.dataTransfer.getData("Text").split(',');
                var dm = document.getElementById(offset[2]);
                dm.style.left = (event.clientX + parseInt(offset[0], 10)) + 'px';
                dm.style.top = (event.clientY + parseInt(offset[1], 10)) + 'px';
                event.preventDefault();
                return false;
            }

            function drag_over(event) {
                event.preventDefault();
                return false;
            }
        </script>
      </head>
      <body ondragover="drag_over(event)" ondrop="drop(event)">
       <ul>
              <li id="txt1" draggable="true" ondragstart="drag_start(event)"> Drag this text </li><br>
              <li id="txt2" draggable="true" ondragstart="drag_start(event)"> Drag me</li>
      </ul>
           <p>I never am really satisfied that I understand anything; because, understand it well as I may, my comprehension can only be an infinitesimal fraction of all I want to understand about the many connections and relations which occur to me, how the matter in question was first thought of or arrived at, etc., etc.</p>
           <p>In almost every computation a great variety of arrangements for the succession of the processes is possible, and various considerations must influence the selections amongst them for the purposes of a calculating engine. One essential object is to choose that arrangement which shall tend to reduce to a minimum the time necessary for completing the calculation.</p>
           <p>Many persons who are not conversant with mathematical studies imagine that because the business of [Babbage’s Analytical Engine] is to give its results in numerical notation, the nature of its processes must consequently be arithmetical and numerical, rather than algebraical and analytical. This is an error. The engine can arrange and combine its numerical quantities exactly as if they were letters or any other general symbols; and in fact it might bring out its results in algebraical notation, were provisions made accordingly.</p>
           <p>The Analytical Engine has no pretensions whatever to originate anything. It can do whatever we know how to order it to perform. It can follow analysis, but it has no power of anticipating any analytical revelations or truths. Its province is to assist us in making available what we are already acquainted with.</p>
    
      </body>
   </html>
5
Lavanya Karanam