允许在 HTML 5 可拖动子元素上选择文本

Posted

技术标签:

【中文标题】允许在 HTML 5 可拖动子元素上选择文本【英文标题】:Allow select text on a HTML 5 draggable child element 【发布时间】:2017-12-04 22:21:31 【问题描述】:

有一个包含可拖动行的表格,其中每一行都是draggable=true,用户如何仍然能够从列中选择文本

<table>
 <thead>..</thead>
 <tbody>
  ..
  <tr draggable="true">
   <td>..</td>
   <td>Cool text but you can't select me</td>
   <td>..</td>
  </tr>
  ..
</tbody>
</table>

另一个简单的例子 (https://codepen.io/anon/pen/qjoBXV)

div 
  padding: 20px;
  margin: 20px;
  background: #eee;


.all-copy p   
  -webkit-user-select: all;  /* Chrome all / Safari all */
  -moz-user-select: all;     /* Firefox all */
  -ms-user-select: all;      /* IE 10+ */
  user-select: all;          /* Likely future */   
    
<div class="all-copy" draggable="true">
      <p>Select me as text</p>
    </div>

【问题讨论】:

不知道是不是只有Mac浏览器,不过还是可以通过右键元素选择文字。 另外,我主观上认为最好有一个清晰且视觉上区分的元素来处理拖放,而不是在您还需要选择文本时允许拖动整行。可拖动区域至少需要与可选文本不同的光标。 是的,不确定在 Windows 中运行的浏览器。 Mozilla 文档说按 Alt 浏览器应该允许选择文本,但从来没有奏效。同意处理程序。我只是遵循规范。 【参考方案1】:

我们需要做两件事。

一件事是限制拖动事件仅在指定区域触发,例如拖动手柄。

另外一点是我们只设置了content类的div上的文字可以选择。我们这样做的原因是已经设置为可拖动的元素,在哪个浏览器上会添加一个默认规则user-select: none

const itemEl = document.querySelector('.item');
const handleEl = document.querySelector('.handle');

let mouseDownEl;

itemEl.onmousedown = function(evt) 
  mouseDownEl = evt.target;


itemEl.ondragstart = function(evt) 
  // only the handle div can be picked up to trigger the drag event
  if (mouseDownEl.matches('.handle')) 
    // ...code
   else 
    evt.preventDefault();
  
.item 
  width: 70px;
  border: 1px solid black;
  text-align: center;


.content 
  border-top: 1px solid gray;
  user-select: text;
<div class="item" draggable="true">
  <div class='handle'>handle</div>
  <div class='content'>content</div>
</div>

【讨论】:

【参考方案2】:

我可以看到这项工作的唯一方法是实际检查哪个元素触发了事件

if (e.target === this) ...

堆栈sn-p

(function (elem2drag) 
  var x_pos = 0, y_pos = 0, x_elem = 0, y_elem = 0;  
  
  document.querySelector('#draggable').addEventListener('mousemove', function(e) 
    x_pos = e.pageX;
    y_pos = e.pageY;
    if (elem2drag !== null) 
        elem2drag.style.left = (x_pos - x_elem) + 'px';
        elem2drag.style.top = (y_pos - y_elem) + 'px';
      
  )

  document.querySelector('#draggable').addEventListener('mousedown', function(e) 
    if (e.target === this) 
      elem2drag = this;
      x_elem = x_pos - elem2drag.offsetLeft;
      y_elem = y_pos - elem2drag.offsetTop;
      return false;
      
  )
  
  document.querySelector('#draggable').addEventListener('mouseup', function(e) 
    elem2drag = null;
  )
)(null);
#draggable 
  display: inline-block;
  background: lightgray;
  padding:15px;
  cursor:move;
  position:relative;

span 
  background: white;
  line-height: 25px;
  cursor:auto;  
<div id="draggable">
  <span>Select me as text will work<br>when the mouse is over the text</span>
</div>

由于Firefox has issue with draggable="true",我使用了不同的拖动方式。

【讨论】:

以上是关于允许在 HTML 5 可拖动子元素上选择文本的主要内容,如果未能解决你的问题,请参考以下文章

使用子元素拖动父元素

如何使嵌套元素在可拖动容器中不可拖动?

当父元素可拖动时如何允许文本框插入符号位置(在鼠标单击时)

jquery可拖动事件更改子元素的css

如何将子元素以外的元素用作拖动手柄?

JCanvas:擦除画布不会擦除可拖动元素