Javascript HTML5 在屏幕上的任意位置拖放

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6230834/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 20:51:42  来源:igfitidea点击:

HTML5 Drag and Drop anywhere on the screen

javascripthtmldrag-and-drop

提问by clicheName

I have a debugger log that I've written in JavaScript for a project I'm working on. The log is basically an <aside>tag in HTML5 that only shows when needed. I wanted to play around with the idea of being able to move the log around the screen, as it may overlap certain things (which is fine for my project). However, I can't seem to figure out how to use HTML5 to properly drag and drop the tag so that it can be placed anywhere on the screen (well, or within a <div>element).

我有一个用 JavaScript 编写的调试器日志,用于我正在处理的项目。日志基本上是<aside>HTML5 中的一个标记,仅在需要时显示。我想尝试一下能够在屏幕上移动日志的想法,因为它可能会重叠某些东西(这对我的项目来说很好)。但是,我似乎无法弄清楚如何使用 HTML5 正确拖放标签,以便将其放置在屏幕上的任何位置(好吧,或在<div>元素内)。

After reading on HTML5's drag and drop support, I have a basic understanding of how it works, but I'm not sure where to start when it comes to allowing the div to be placed anywhere (it's z-index is a high value, so as I said, overlapping is fine).

在阅读了 HTML5 的拖放支持后,我对它的工作原理有了基本的了解,但是当涉及允许将 div 放置在任何地方时我不确定从哪里开始(它的 z-index 是一个高值,所以正如我所说,重叠很好)。

Any suggestions?

有什么建议?

Oh, and I'd like to try and avoid using external libraries for this project, wherever possible. I'm trying to do this in pure JavaScript/HTML5.

哦,我想尽可能避免在这个项目中使用外部库。我试图在纯 JavaScript/HTML5 中做到这一点。

回答by robertc

Drag and drop doesn't move elements around, if you want the element to move when you drop it then you have to set the new position of the element in the drop event. I've done an examplewhich works in Firefox and Chrome, here are the key points:

拖放不会移动元素,如果您希望元素在放置时移动,则必须在放置事件中设置元素的新位置。我已经做了一个在 Firefox 和 Chrome 中工作的例子,这里是要点:

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));
} 

The dragstartevent works out the offset of the mouse pointer from the left and top of the element and passes it in the dataTransfer. I'm not worrying about passing the ID because there's only one draggable element on the page - no links or images - if you have any of that stuff on your page then you'll have to do a little more work here.

dragstart事件计算鼠标指针距元素左侧和顶部的偏移量,并将其传递到dataTransfer. 我不担心传递 ID,因为页面上只有一个可拖动元素 - 没有链接或图像 - 如果您的页面上有任何这些内容,那么您将不得不在这里做更多的工作。

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;
}

The dropevent unpacks the offsets and uses them to position the element relative to the mouse pointer.

drop事件解包偏移量并使用它们相对于鼠标指针定位元素。

The dragoverevent just needs to preventDefaultwhen anything is dragged over. Again, if there is anything else draggable on the page you might need to do something more complex here:

dragover事件只需要preventDefault在任何拖过。同样,如果页面上还有其他可拖动的内容,您可能需要在这里做一些更复杂的事情:

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

So bind it to the document.bodyalong with the dropevent to capture everything:

因此,将其document.bodydrop事件一起绑定以捕获所有内容:

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

If you want this to work in IE you'll need to convert the asideto an aelement, and, of course, all the event binding code will be different. The drag and drop API doesn't work in Opera, or on any mobile browsers as far as I'm aware. Also, I know you said you don't want to use jQuery, but cross browser event binding and manipulating element positions are the sort of things that jQuery makes much easier.

如果你想让它在 IE 中工作,你需要将 转换aside为一个a元素,当然,所有的事件绑定代码都会不同。据我所知,拖放 API 在 Opera 或任何移动浏览器中都不起作用。另外,我知道你说过你不想使用 jQuery,但是跨浏览器事件绑定和操作元素位置是 jQuery 使事情变得容易得多的事情。

回答by Ingvi

I adjusted a bit robertc's great answer for cases of multiple items. Here the secondclass name is just for another position.

对于多个项目的情况,我调整了一点robertc的好答案。这里的second类名只是为了另一个位置。

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

Add the data-item attribute to the setDatafunction.

将 data-item 属性添加到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'));
}

Target the element that is dragged.

定位被拖动的元素。

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;
}

And loop through all elements with a class dragme.

并使用 class 循环遍历所有元素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);
}

pen

钢笔

回答by Lavanya Karanam

Thanks for your answer. It works great in Chrome and Firefox. I tweaked it to work in IE.Below is the code.

感谢您的回答。它在 Chrome 和 Firefox 中运行良好。我调整它以在 IE 中工作。下面是代码。

 <!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>