html5 可拖动隐藏原始元素

html5 draggable hide original element

当开始使用 HTML5 可拖动属性拖动元素时,原始元素仍然可见,所以我最终有两个元素可见,而不是一个。

如何才能只显示被拖动的元素(原来的元素应该暂时隐藏)。

<script>
  function startDrag() {
    // hide initial element
  }

  function endDrag() {
    // reset initial element
  }
</script>

<div class="draggable" draggable="true"
  ondragstart="startDrag(event)"
  ondragend="endDrag(event)"
></div>

这是一个显示问题的 jsfiddle https://jsfiddle.net/gjc5p4qp/

您可以使用一个 hacky 解决方案来成功。本机可拖动性不允许 CSS 样式,例如:opacity:0;visibility:hiddendisplay:none.

但您可以使用:transform:translateX(-9999px).

function startDrag(e) {
  let element = e.target;
  
  element.classList.add('hide');
}

function endDrag(e) {
  let element = e.srcElement;
  
  element.classList.remove('hide');
}
.draggable {
  border-radius: 4px;
  background: #CC0000;
  width: 40px;
  height: 40px;
}
.hide {
  transition: 0.01s;
  transform: translateX(-9999px);
}
<div
  class="draggable"
  draggable="true"
  ondragstart="startDrag(event)"
  ondragend="endDrag(event)"
/>

我已经用解决方案更新了你的JSFiddle

[编辑]:

使用 requestAnimationFrame 代替 setTimeout 更新了 JSFiddle example with 建议。

[编辑 2]:

通过 添加 transition CSS 属性 而不是使用 requestAnimationFrame 更新了更好的解决方案,它将处理从脚本编写转移到渲染。

由于简单地设置 visibility: hidden 不起作用,我找到了另一个有点 hacky 的解决方案:在拖动事件开始后一毫秒设置 visibility: hidden

function startDrag(e) {
  setTimeout(function() {
    e.target.style.visibility = "hidden";
  }, 1);
}

function endDrag(e) {
  setTimeout(function() {
    e.target.style.visibility = "";
  }, 1);
}
body {
  display: inline-block;
  outline: 1px solid black;
}
.draggable {
  border-radius: 4px;
  background: #CC0000;
  width: 40px;
  height: 40px;
}
<div class="draggable" draggable="true" ondragstart="startDrag(event)" ondragend="endDrag(event)">

</div>

找到这个:

用一个干净的解决方案来隐藏 dragover 处理程序中的 source/original 元素。

var dragging;
function dragstart(e) {
  dragging = $(this);
}

function dragover(e) {
  dragging.hide();
}

function dragend(e) {
  if (dragging) {
    dragging.show();
    dragging = undefined;
  }
}

这可以在没有以前答案的 hack trick 的情况下实现。

重点是监听drag事件,而不是dragstart

//listen to drag event, not dragstart!
document.querySelector(".draggable").addEventListener("drag", (e)=>{
  e.target.classList.add("dragging");
});
document.querySelector(".draggable").addEventListener("dragend", (e)=>{
  e.target.classList.remove("dragging");
});
.draggable {
  width: 200px;
  height: 30px;
  background-color:#5856d6;
  text-align:center;
  line-height:30px;
}

.dragging {
  background: transparent;
  color: transparent;
  border: 1px solid #5856d6;
}
<div draggable="true" class="draggable">Drag me!</div>

Filipe 的回答真的很有帮助。如果 setTimeoutrequestAnimationFrame 对您不起作用。尝试添加过渡。

transition: transform 0.01s;
transform: translateX(-9999px);

您可以将此代码添加到您的 dragStart 事件中:

event.dataTransfer.setDragImage(new Image(), 0, 0); // Hide the dragged element

它将隐藏您的目标拖动元素。

如何隐藏元素

如果你想隐藏你的元素,你可以使用 CSS 属性 visibility:hidden or display:none.

我推荐使用 visibility 属性 因为它隐藏了一个元素而不改变文档的布局。但是,如果您的元素有孩子并且想将它们隐藏到其中,则需要在每个孩子上设置 visibility:inherit

何时隐藏它

您使用 dragstart 事件是正确的。但是由 draggable 属性创建的元素的克隆出现在 dragstart 事件的末尾。

因为 JavaScript 引擎是一个 single-threaded 解释器,如果您选择在此处隐藏它,您的元素将被屏蔽为它的克隆,它将复制 属性 visibility:hidden。事实上,为了避免这种情况,您需要在 Javascript callstack.

中创建克隆后将其隐藏

为此,请使用 setTimout() 函数并将其设置为 0 毫秒。这样,在创建他的克隆之后,将原始元素的掩码放在堆栈的末尾。

在拖动结束时,要使其重新出现,您只需通过在 dragend 事件中调用 visibility:visible 将元素设置为可见。

代码示例

例如,代码可能如下所示:

<div 
    class="draggable" 
    draggable="true" 
    ondragstart="startDrag(event)" 
    ondragend="endDrag(event)" 
    style="background: #e66465; color:white; width:80px; height:20px; text-align:center;">
    Drag me
</div>

<script>
    function startDrag(e) {
        setTimeout(function(){
            e.target.style.visibility = "hidden";
        }, 0);
    }
    function endDrag(e){
        e.target.style.visibility = "visible";
    }
</script>