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

HTML5 Drag and Drop anywhere on the screen

本文关键字:任意 位置 拖放 屏幕 HTML5      更新时间:2023-09-26

我有一个调试器日志,我用JavaScript为正在处理的项目编写了它。该日志基本上是HTML5中的<aside>标记,只在需要时显示。我想考虑一下可以在屏幕上移动日志的想法,因为它可能会与某些内容重叠(这对我的项目来说很好)。然而,我似乎不知道如何使用HTML5来正确地拖放标签,以便将其放置在屏幕上的任何位置(好吧,或者<div>元素内)。

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

有什么建议吗?

哦,我想尽可能避免在这个项目中使用外部库。我正在尝试用纯JavaScript/HTML5来实现这一点。

拖放不会移动元素,如果您希望元素在拖放时移动,则必须在拖放事件中设置元素的新位置。我已经做了一个在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));
} 

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

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

当拖动任何内容时,dragover事件只需要preventDefault。同样,如果页面上还有其他可拖动的内容,您可能需要在此处执行更复杂的操作:

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

因此,将其与document.body以及drop事件绑定以捕获所有内容:

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

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

感谢您的回答。它在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>

我稍微调整了一下robertc在多个项目的情况下的出色答案。这里的second类名只是用于另一个位置。

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

将数据项属性添加到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'));
}

以拖动的元素为目标。

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

并使用类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);
}

有时,body没有页面的确切尺寸。在这种情况下,不能将元素拖动到body的边界之外。

以下是最适合我的解决方案:

const myElement = document.getElementById("my-element");
myElement.addEventListener("dragstart", (evt) => {
  evt.dataTransfer.setData("id", "my-element");
  const boundingRect = myElement.getBoundingClientRect();
  const offset = {
    x: evt.clientX - boundingRect.left,
    y: evt.clientY - boundingRect.top,
  };
  evt.dataTransfer.setData("offset", JSON.stringify(offset));
});
document.documentElement.addEventListener("dragover", (evt) => {
  evt.preventDefault();
  evt.dataTransfer.dropEffect = "move";
});
document.documentElement.addEventListener("drop", (evt) => {
  evt.preventDefault();
  if (evt.dataTransfer.getData("id") === "my-element") {
    const offset = JSON.parse(evt.dataTransfer.getData("offset"));
    const xPos = evt.clientX - offset.x;
    const yPos = evt.clientY - offset.y;
    myElement.style.left = `${xPos}px`;
    myElement.style.top = `${yPos}px`;
    myElement.style.bottom = "auto";
    myElement.style.right = "auto";
  }
});
#my-element {
  position: fixed;
  padding: 10px;
  background: yellow;
  white-space: nowrap;
  display: inline-block;
}
<div id="my-element" draggable="true">Drag me anywhere</div>