有没有办法拖动和复制,但防止“可拖动”的拖放? (JavaScript)

问题描述

现在我有一个功能性的拖动和复制。我想知道是否有任何方法可以拖动副本,但不能删除。例如,如果用户按住 shift 键,他/她可以快速单击并放下克隆,而不会放下拖动的元素。如果在文档中上下搜索并没有找到任何东西。

这是我的代码 https://jsfiddle.net/jado66/f8b4ms36/2/ :

<!DOCTYPE html>
<html>
<head>
  <title>Drag copy</title>
</head>
<style>

* {user-select: none; } 
.cell {width:50px;height:50px;
  }
img {width:50px;height:50px;cursor: move;}
table td #dropTable td:hover{background: #dedede;}
#dropTable {
    border-spacing: 5px;
    border: 1px solid #dedede;
}
.droppable:hover{
    transform: scale(1.05);
    transition-duration: 0.3s;
}

#dropTable tbody { height:300px; overflow-y:auto;  }

</style>

<body>
   

     <!-- Drag Table -->
    
        <table style="border-spacing: 5px;">
            <tr>
                <td id="image1">
                    <div class = "cell" ondrop="drop(event)" ondragover="allowDrop(event)">
                        <img class = "droppable newGate" src="droppable" src="https://picsum.photos/500/500?random=1"   
                      ondragstart="dragStart(event)" id="1" draggable="true"/> </div>
                </td>
                <td id="image2">
                    <div class = "cell " ondrop="drop(event)" ondragover="allowDrop(event)">
                        <img class = "droppable" src="https://picsum.photos/500/500?random=2"   
                      ondragstart="dragStart(event)" id="2" draggable="true" /> </div>
                </td>
    
            </tr>
        </table>
        <hr>
        <!-- Drop Table -->
        <table>
            <tr>
                <td>
                    <table id="dropTable" >
                    <tr >
                        <td> <div class = "cell"></div></td> 
                        <td> <div class = "cell" ></div></td>
                        <td> <div class = "cell" ></div></td>
                        <td> <div class = "cell" ></div></td>
                    </tr>
                    <tr>
                        <td> <div class = "cell" ></div></td>
                        <td> <div class = "cell" ></div></td>
                        <td> <div class = "cell" ></div></td>
                        <td> <div class = "cell" ></div></td>
                    </tr>
                    </tr>
                        <td> <div class = "cell" ></div></td>
                        <td> <div class = "cell" ></div></td>
                        <td> <div class = "cell" ></div></td>
                        <td> <div class = "cell" ></div></td>
                    </tr>
                    </table>
                </td>
            </tr>
        </table>
    <script>
    
const cells = document.querySelectorAll(".cell:empty"); //We only want to add event listeners to empty cells
for (const cell of cells){
    cell.addEventListener('dragover',allowDrop);
    cell.addEventListener('drop',drop);
}

function dragStart(evt)
{
    evt.dataTransfer.setData("Text",evt.target.id);
}

function drop(evt)
{
    var data = evt.dataTransfer.getData("Text");
    var nodecopy = document.getElementById(data).cloneNode(true);
    nodecopy.id = Date.Now(); /* We cannot use the same ID */
    evt.target.appendChild(nodecopy);
    
    if (evt.shiftKey){
        console.log("Shift key pressed. copy but keep drag");
      //Invoke drag command,or prevent drop,etc.
    }
}

function allowDrop(ob)
{
    ob.preventDefault();
}
    
    </script>
    </body>
    </html>

解决方法

简而言之,没有

要回答您的问题是否可以在用户释放鼠标按钮时阻止放置事件:否。

来自the spec

否则,如果用户结束了拖放操作(例如在鼠标驱动的拖放界面中通过释放鼠标按钮),或者如果拖动事件被取消,那么这将是最后一次迭代。

然而,当用户放下节点时,可能会立即触发一个新的 DragStart 事件,但我无法让它工作。在规范中找不到任何关于不可能的任何内容,但我可能是错的。

针对您的特定用例的解决方法

这只是一个概念证明,代码看起来不太好,我确定它有错误,但它可以满足您的要求:https://jsfiddle.net/y9Lpxdea/3/。按住 shift 键并在插槽上拖动以克隆当前持有的对象。

通过将要从 onDragStart 克隆的元素的 id 存储在一个变量中(不在 DataTransfer 对象中作为 DataTransfer.getData() is only accessible on the drop event),您可以访问onDragEnter 事件中当前持有的对象,然后从那里复制子项。我保留了当前的拖放功能,而没有保持完整的 shift 键。

let dragId = null;

function dragStart(evt)
{
    evt.dataTransfer.setData("Text",evt.target.id);
    dragId = evt.target.id;
}

function dragEnter(evt)
{
    if (evt.shiftKey && dragId){
        var nodeCopy = document.getElementById(dragId).cloneNode(true);
        nodeCopy.id = Date.now(); /* We cannot use the same ID */
        evt.target.innerHTML = "";
        evt.target.appendChild(nodeCopy);
    }
}

function drop(evt)
{
    var data = evt.dataTransfer.getData("Text");
    var nodeCopy = document.getElementById(data).cloneNode(true);
    nodeCopy.id = Date.now(); /* We cannot use the same ID */
    evt.target.appendChild(nodeCopy);
    dragId = null;
}