如何防止拖累孩子,但允许拖累父母?

Posted

技术标签:

【中文标题】如何防止拖累孩子,但允许拖累父母?【英文标题】:How do I prevent drag on a child, but allow drag on the parent? 【发布时间】:2011-10-14 10:58:42 【问题描述】:

我有一个用户可以拖动的 div,在该 div 内是一个跨度,其中包含一些我希望允许用户选择的文本(因此他们不能拖动它)。如何允许 div 拖动,但不允许 span?

dragstart 事件在 div 上。

我可能忽略了一些简单的事情。我在 div 上尝试了 draggable=true,在跨度上尝试了 draggable=false。那没有用。尝试在 dragstart 上返回 false,但也没有用。

dragstart(大致):

var jTarget = $(e.target);
if ((jTarget.is('div.header') || (jTarget.parents('div.header')) 
       && !jTarget.is('a, input, span'))) 

   e.originalEvent.dataTransfer.setData("Text", "test");

else

   if(e.preventBubble)
      e.preventBubble();
   if(e.stopPropagation)
      e.stopPropagation();
   return false;//???

if else 部分按我的预期工作,但我无法停止拖动并允许选择。

【问题讨论】:

不要认为这是可能的 - 尽管您可以通过在 div 中提供拖动事件可以附加到的拖动句柄来解决它,从而使内部文本可选择。无法区分单击/拖动以移动和单击/拖动以突出显示。它们都只是鼠标按下,然后是鼠标移动。 您的dragstart 处理程序中有什么代码?请将其添加到您的问题中。 @Marc B - 我开始认为我可能不得不这样做。虽然它不是最佳的,因为我的跨度可能占用 1.5 行,我希望其他 0.5 行是可拖动的。那将是相当困难的。而且,这个对象是标题对象,因此添加另一个标题用于拖动目的是不可能的。 【参考方案1】:

如果您想真正取消拖动并使其不被父拖动处理程序注意到,您需要 preventDefaultstopPropagation

<div draggable="true" ondragstart="console.log('dragging')">
    <span>Drag me! :)</span>
    <input draggable="true"
           ondragstart="event.preventDefault();
                        event.stopPropagation();"
           value="Don't drag me :(">
</div>

如果没有stopPropagation,即使会阻止默认行为(event.defaultPrevented == true),仍会调用父级ondragstart。如果您在该处理程序中有不处理这种情况的代码,您可能会看到一些细微的错误。

当然你也可以把上面的javascript放在element.addEventListener('dragstart', ...)里面。

【讨论】:

input 元素上添加你不想被拖动的 draggable="true" 是这个答案的一个微妙但关键的方面,乍一看似乎违反直觉,但对于获得输入的ondragstart 事件触发。我只是将其称为 b/c,这是我所缺少的部分,该答案帮助我找到了它,并且可能也适用于其他人。 当输入有 draggable="true" 时,我无法让 &lt;input&gt;ios(或任何触控设备)上正常工作。焦点轮廓显示和键盘弹出,但无法输入任何内容。任何解决方法? jsfiddle.net/yjk8uhwr【参考方案2】:

只是发布,以防有​​人搜索它有类似的问题

element.addEventListener('mousedown', function()  this.parentNode.setAttribute("draggable", false); );
element.addEventListener('mouseup', function()  this.parentNode.setAttribute("draggable", true); );

为我工作

【讨论】:

一个不错且简单的解决方案。 “mouseenter”和“mouseleave”事件对我来说效果更好,很难。 有趣,对我来说实际上 mouseentermouseleave 有效,mousedown / mouseup 无效。有了这些,我仍然无法在嵌套的input 中选择文本。无论如何,好主意@mech!【参考方案3】:

您可以在ondragstart时将子元素更改为可拖动并防止默认,这将保留子元素上的常规行为而父元素仍可拖动

function drag(e) if(e.target.type=="range")e.preventDefault();/*rest of your code*/  

html:

<input type="range" draggable="true" ondragstart="drag(event)">

【讨论】:

为我工作!并且似乎是“最干净”的解决方案,与 mousedown 处理程序相比,imo 与拖动事件一开始就没有任何关系。作为此解决方案的补充,我使用单独的函数来取消任何子元素的拖动,因此实际的拖动函数不会因条件而变得混乱,什么不是!可以叫它dragCancel什么的;)【参考方案4】:

在 span 上放置一个 mousedown 处理程序并在那里停止事件传播。

【讨论】:

经过测试(我有一个类似的问题),至少它不会发生拖动,但其他任何事情都不会发生,不可能选择文本,如果对象是 contenteditable 你可以不设置光标...【参考方案5】:

在我的应用程序中,我无法使用此处列出的任何其他解决方案。这对我有用:

ondragstart="event.preventDefault();" draggable="false"

在我的具体情况下,它是 div 内的文本输入。

【讨论】:

event.preventDefault();与设置 draggable="false" 无效;参与 event.preventDefault();您需要设置 draggable="true"。否则没有理由将该行包含在您的元素中。【参考方案6】:

我受到这里的一些答案的启发,我想我想出了最干净、最可重用的解决方案。我使用鼠标按下事件来检查元素是否应该是可拖动的。我通过验证它是否具有仅分配给可拖动元素的特定类名来做到这一点。在鼠标向上事件中,我遍历所有带有该类标记的元素并将它们的可拖动值设置回 true。

如果输入节点是可拖动 div 的深层子节点,这可能会中断,但是您可以使用与鼠标向上事件中相同的算法并将所有值设置为 false。

document.addEventListener('mousedown', function (event) 
	var clickedElem = event.target;
    if(!clickedElem.classList.contains("drop_content"))
        clickedElem.parentElement.setAttribute("draggable",false);
    
, false);

document.addEventListener('mouseup', function () 
    var boxes = document.querySelectorAll(".drop_content");
    for(var i = 0; i < boxes.length; i++)
        boxes[i].setAttribute("draggable",true);
    
, false);
div
  display:block;
  background: black;
  padding: 5px;
  margin: 2px;
<html>
  <body>
    <div class="drop_content" draggable="true">
      <input value="Can't drag me">
    </div>
    <div class="drop_content" draggable="true">
      <input value="Can't drag me either">
    </div>
  </body>
</html>

【讨论】:

以上是关于如何防止拖累孩子,但允许拖累父母?的主要内容,如果未能解决你的问题,请参考以下文章

防止孩子增加父母的宽度[重复]

如何防止孩子在 fork() 之后干扰父母的标准输入

不允许更改核心数据关系,但最终允许删除子项

防止父母李+李携带给孩子

防止绝对孩子扩展父母

防止孩子走丢,除了定位手机这些方法值得收藏