HTML5拖放& drop placeholder将parentNode设置为null onLeave(js vanilla)

时间:2017-07-14 18:08:14

标签: javascript html5 drag-and-drop draggable

对于我自己的网站我试图创建一个编辑器(基于contentEditables和HTML5拖放功能)。

这是小提琴:https://jsfiddle.net/5bw320zo/1/ 请注意代码很乱,它只是一个POC

问题:

每次悬停 占位符时,占位符的parentNode似乎都设置为null。

  

未捕获的TypeError:无法读取属性' removeChild'为null       在_detach       在HTMLDivElement._handleDragLeave

代码说明:

我在初始化时创建了一个简单的div元素:

placeholder = d.createElement('div');
placeholder.setAttribute('style', 'height: 25px; background-color: red;');

每个容器都有它自己的事件:

_on(elements, 'dragenter', _handleDragEnter);
_on(elements, 'dragover', _handleDragOver);
_on(elements, 'dragleave', _handleDragLeave);
_on(elements, 'drop', _handleDrop);

悬停时我会检查它是否有子项如果不是我只是追加元素,否则我会在之前或之后添加元素(取决于鼠标高度的位置):

function _handleDragOver(e) {
  var targetBoundingBox,
    targetMouseY;

  targetBoundingBox = e.target.getBoundingClientRect();
  targetMouseY = e.pageY - targetBoundingBox.top;

  if (e.target.hasChildNodes()) {
    // TODO check Y axis (/2)
  } else {
    c.log('within');
    _within(e.target, placeholder);
  }
}

在元素鼠标离开时,我将占位符(global var)与它自己的父级分开:

function _handleDragLeave(e) {
  placeholder.parentNode.removeChild(placeholder);
}

它让我不知所措。在休假时检查源时,占位符元素仍然在正确的位置。有任何想法吗?

如果你们有更好的想法来整合占位符,请告诉(没有jquery或现有的库)。

2 个答案:

答案 0 :(得分:1)

这里几乎没有问题......

首先,当您将_handleDragOver悬停在占位符上时,它始终会执行其他条件,因为它没有子级。

function _handleDragOver(e) {
    var targetBoundingBox,
      targetMouseY;

    targetBoundingBox = e.target.getBoundingClientRect();
    targetMouseY = e.pageY - targetBoundingBox.top;

    if (e.target.hasChildNodes()) {
      // TODO check Y axis (/2)
    } else {
      c.log('within');
      _within(e.target, placeholder); //<-- this guy
    }
  }

dragOver在将鼠标悬停在有效的放置目标上时不断触发。

接下来,_within功能:

  function _within(target, element) {
    target.appendChild(element);
  }

如果占位符尚未被_detach功能删除,那么这个小家伙会给您带来麻烦。如果您要放置占位符,并且它尚未被删除,那么您将尝试将其附加到自身...这将导致fireun为unfun类型。

现在是_detach

  function _detach(element) {
    element.parentNode.removeChild(element);
  }

这会在您的_handleDragLeave函数中调用。放下拖动时,dragLeave事件会触发删除占位符。

这里是错误的来源...将鼠标悬停在占位符上会导致它被dragLeave分离,但随后它会被dragOver追回,依此类推,导致闪烁。你得到的错误是由于一个drop事件试图删除占位符引起的,当它已经被dragLeave删除但还没有被dragOver重新出现之后再尝试再次删除它。

答案 1 :(得分:1)

过去我做过一些拖放工作。我的问题是,当我使用拖放操作时,我没有注意到你需要使用DataTransfer对象。

DataTransfer Object

JS fiddle example

第1步:拖动处理程序:

function _handleDragStart(e) {
  e.dataTransfer.setData('myData', 'somedata');
  e.dataTransfer.effectAllowed = 'move';
  //no e.preventDefault() here or it will not work.
}

第2步:拖过处理程序:

function _handleDragOver(e) {
  var data = e.dataTransfer.getData('myData');
  if(data && //is this valid drop data){
    e.dataTransfer.dropEffect = 'move';
    e.preventDefault();
  }
}

第3步:删除处理程序:

function _handleDrop(e) {
  var data = e.dataTransfer.getData('myData');
  if(data && //is this valid drop data){
    //do something with your dropped data.
    //re-render component inside editor-container
    e.preventDefault();
  }
}

第4步:拖动结束处理程序:

function _handleDragEnd(e) {
  e.dataTransfer.clearData();
  //Check if drop was completed and do cleanup.
  //remove component from editor-item-list
}

e.dataTransfer.dropEffect用于告诉拖放API可以执行放置操作。如果没有这个,drop永远不会触发。它还用于更改光标的图标。

e.dataTransfer.setData只将数据作为字符串。这可以通过将其转换为JSON来解决,也可以在编辑器中自己处理数据传输。

我发现在执行拖放操作时使用数据而不是DOM元素会更简单。传输数据并在删除操作后重新呈现它。

更新1

e.dataTransfer.getDatadrag over中,{59} drag end 无效。也许你最好自己做数据传输。请记住,您仍需要设置dropEffect