子元素允许拖放

时间:2014-06-10 22:28:29

标签: javascript html html5 drag-and-drop

我在html5中拖拽时遇到了一个奇怪的问题。

面板A有一个可以拖动的元素类型列表。面板B是拖动元素的位置。面板C和D是您可以拖动元素的其他位置,您可以在面板B,C和D之间拖动和重新排列元素。

我的问题是我能够拖动一个元素并将其放在其中一个面板内的另一个元素内部,我不希望用户能够做到这一点。这些面板的子元素没有附加任何类型的javascript或与拖动相关的属性,但它们目前允许将元素拖入其中。

我已尝试附加" ondrop ='返回false;'"并且" ondragover ='返回false;'",但两者都没有效果。

当然有一种方法可以关闭“允许拖入'元素上的属性?

这是我的代码:

<div id="elem-002" draggable="true" ondragstart="drag(event)">content</div>

主要小组:

<div id="panel-b" ondrop="drop(event)" ondragover="allowDrop(event)">
  <div id="elem-001" draggable="true" ondragstart="drag(event)">content</div>
</div>

JS:

function allowDrop(ev) {
    ev.preventDefault();
}

function drag(ev) {
    ev.dataTransfer.setData("Text", ev.target.id);
}

function drop(ev) {
    ev.preventDefault();
    var data = ev.dataTransfer.getData("Text");
    ev.target.appendChild(document.getElementById(data));
}

另一种说法:我能够拖动我的&#34; elem-002&#34;直接进入&#34; elem-001&#34;,这是一个已经被拖入的元素。这导致了我不想发生的元素嵌套。我该如何防止这种情况?

5 个答案:

答案 0 :(得分:11)

基本上,您必须在ev.dataTransfer.dropEffect中设置正确的allowDrop。对于您的draggable元素,它应该是"none"(不允许删除),以及其他所有内容(或允许删除的任何其他元素)"all"

进一步阅读dropEffect

实例:

window.allowDrop = function(ev) {
    ev.preventDefault();
    if (ev.target.getAttribute("draggable") == "true")
        ev.dataTransfer.dropEffect = "none"; // dropping is not allowed
    else
        ev.dataTransfer.dropEffect = "all"; // drop it like it's hot
};

window.drag = function(ev) {
    ev.dataTransfer.setData("id", ev.target.id);
};

window.drop = function(ev) {
    ev.preventDefault();
    var id = ev.dataTransfer.getData("id");

    var dragged = document.getElementById(id);
    ev.target.appendChild(dragged);
    dragged.className += " dropped";
};
.drag {
    display: inline-block;
    padding: 5px;
    background: rgba(0, 0, 0, 0.2);
    margin: 2px;
}

.dropzone {
    background: #ccc;
    padding: 5px;
    margin-top: 10px;
}
<div id="first" class="drag" draggable="true" ondragstart="drag(event)">1</div>
<div id="second" class="drag" draggable="true" ondragstart="drag(event)">2</div>

<div class="dropzone" ondrop="drop(event)" ondragover="allowDrop(event)"><div id="third" class="drag dropped" draggable="true" ondragstart="drag(event)">3</div></div>

答案 1 :(得分:4)

我不确定这是否是最佳解决方案,但我确实提出了一些建议。

我将drop(ev)更改为:

function drop(ev) {
    ev.preventDefault();

    if (!ev.target.getAttribute("ondrop"))
        return false;

    var data = ev.dataTransfer.getData("Text");
    ev.target.appendChild(document.getElementById(data));
}

这或其变体可防止任何内容被丢弃到未明确定义“ondrop”的元素中。

答案 2 :(得分:0)

我正在使用自定义拖放,通过拖动[enter | over | leave]&amp;混合拖动元素的鼠标[向下移动]。放在另一个元素上。我正在使用自定义事件来触发/触发/调度drop事件。这并没有真正对手头的问题产生影响,只是想给出背景。

Anyhoo,我遇到了同样类型的问题,经过一段时间的搜索,并进行了一些调试,我意识到事件。[target | srcElement]实际上是发送的元素&#39;事件。所以我最终做的是; 拒绝[target | srcElement]不是&#39;这个&#39;活动的元素以及这个&#39;不包含[target | srcElement](即不是其中一个子节点),只有这样才允许进一步处理;

// Drop Event Handler
function dropEventHandler(event) {
    event = event || window.event;
    var target = event.target || event.srcElement;

    if (this !== target && this.contains(target)) {
        // Use if not a proper/normal event, this should stop any further 
        //   processing of the event 
        // if (event.stopPropagation) event.stopPropagation();  // Standard model
        // else event.cancelBubble = true;                       //IE

        // Stops the default action of an element from happening
        // Use the event.isDefaultPrevented() method to check whether 
        //   the preventDefault() method was called for the event
        if (event.preventDefault) event.preventDefault();   // Standard model
        else event.returnValue = false;                      //IE

        return false;
    }
    // Process drop event
}

在Chrome,FF,Opera,IE Edge&amp;&amp; Windows 10上的IE 11 [仿真7-11], 还测试了Windows 7 [IE7和IE8兼容性]模式下的IE v8.0.7601.17514。

答案 3 :(得分:0)

我通过允许用户放弃放置目标内的任何位置来改进@Zerkeras的答案,但是,如果用户碰巧掉落在放置目标内的元素内部而不是失败,那么它只是调整元素被丢弃的地方。

function drop(ev) {
        ev.preventDefault();
        var data = ev.dataTransfer.getData("text");
        var i = 0;
        var element = ev.target
        while (!element.getAttribute("ondrop") && i < 3) {
            console.log("recalibrating");
            element = element.parentElement;
            i++;
        }
        element.appendChild(document.getElementById(data));
    }

注意,我已经添加了一个任意3来逃离while循环,因为我怀疑while循环并不能保证逃脱。在这个特殊情况下,这是我的纯粹偏执,但在我测试时它非常有用。

我使用新变量element的原因是因为直接修改ev.target似乎是不可能的(我没有认为不变性在JavaScript中起作用?如果有人知道为什么会这样,我&#39 ;好奇)。所以我的while循环从未退出,这就是为什么你在那里看到我的偏执逃避条款。

答案 4 :(得分:0)

如果我理解正确,问题是预期放置目标的子级也可以允许拖放交互。因此,如果您将“this”添加到 ondrop 调用中,您就可以知道哪个元素实际上是预期的元素。然后,您可以附加到您想要的元素或以其他方式与其交互。请参阅我的其他问题/解决方案。

Image tries to add to self on drag/drop interaction