拖放 API 实施的错误

Bug with Drag and Drop API implementation

在这些天里,我一直在尝试学习如何实现拖放 API,但我 运行 遇到了一个我无法修复的错误。实际上,如果我通过拖动交换第一个和第二个框,当我 select 和 header 并将其拖动到第二个框时,就会发生错误!这只是个案,但还有更多。我想看看调试会发生什么,但我错过了一些东西。下面是错误和代码的屏幕截图:

bug

let dragSrcEl = null;

function handleDragStart(e) {
  this.classList.add('dnd__element--dragStart');

  console.log(this);
  dragSrcEl = this;

  e.dataTransfer.effectAllowed = 'move';
  e.dataTransfer.setData('text/html', this.innerHTML);
}

function handleDragOver(e) {
  if (e.preventDefault) {
    e.preventDefault();
  }

  e.dataTransfer.dropEffect = 'move';
  return false;
}

function handleDragEnter(e) {
  this.classList.add('dnd__element--dragOver');
}

function handleDragLeave(e) {
  this.classList.remove('dnd__element--dragOver');
}

function handleDragEnd(e) {
  this.classList.remove('dnd__element--dragStart');

  items.forEach(function(item) {
    item.classList.remove('dnd__element--dragOver');
  });
}

function handleDrop(e) {
  if (e.stopPropagation) {
    e.stopPropagation(); // stops the browser from redirecting.
  }

  if (dragSrcEl != this) {
    dragSrcEl.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text/html');
  }

  return false;
}

const items = document.querySelectorAll('.dnd__element');
items.forEach(function(item) {
  item.classList.remove(
    'dnd__element--dragStart',
    'dnd__element--dragEnd',
    'dnd__element--dragOver'
  );
  item.addEventListener('dragstart', handleDragStart, false);
  item.addEventListener('dragover', handleDragOver, false);
  item.addEventListener('dragenter', handleDragEnter, false);
  item.addEventListener('dragleave', handleDragLeave, false);
  item.addEventListener('drop', handleDrop, false);
  item.addEventListener('dragend', handleDragEnd, false);
});
.dnd__element {
  cursor: move;
  border: 3px solid #777;
  background-color: #ddd;
  padding: 1rem;
  border-radius: 0.5rem;
  float: left;
}

.dnd__element--dragStart {
  opacity: 0.4;
}

.dnd__element--dragEnd {
  opacity: 1;
}

.dnd__element--dragOver {
  border: 3px dotted #666;
}

.dnd__drag-zone {
  height: 20rem;
  background-color: cornsilk;
}

.heading-tertiary {
  display: block;
  background-color: darkkhaki;
  padding: 2rem 1rem;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <section class="section-dnd">
    <div class="dnd__drag-zone">
      <h3 class="heading-tertiary">Drag zone</h3>
      <div class="dnd__element dnd__element--dragStart" id="d1" draggable="true">
        Box 1
      </div>
      <div class="dnd__element dnd__element--dragEnd" id="d2" draggable="true">
        Box 2
      </div>
      <div class="dnd__element dnd__element--dragOver" draggable="true">
        Box 3
      </div>
    </div>
  </section>
</body>

</html>

最简单的方法是依赖“handleDragStart()”,因为它只能用 3 个有效项目中的 1 个来调用。因此,在该处理程序中设置一个测试变量(例如 started = true;)并在“handleDragEnter()”和“[=27=”中检查它 (if (started)) ]handleDrop()'.

(在'handleDrop()'中将'started'重置为false)...

工作示例:

var started = false;
let dragSrcEl = null;

function handleDragStart(e) {
  this.classList.add('dnd__element--dragStart');

  started = true;
  dragSrcEl = this;

  e.dataTransfer.effectAllowed = 'move';
  e.dataTransfer.setData('text/html', this.innerHTML);
}

function handleDragOver(e) {
  if (e.preventDefault) {
    e.preventDefault();
  }

  e.dataTransfer.dropEffect = 'move';
  return false;
}

function handleDragEnter(e) {
  if (started) this.classList.add('dnd__element--dragOver');
}

function handleDragLeave(e) {
  this.classList.remove('dnd__element--dragOver');
}

function handleDragEnd(e) {
  this.classList.remove('dnd__element--dragStart');

  items.forEach(function(item) {
    item.classList.remove('dnd__element--dragOver');
  });

  started = false;
}

function handleDrop(e) {
  if (e.stopPropagation) {
    e.stopPropagation(); // stops the browser from redirecting.
  }

  if (started && dragSrcEl != this) {
    dragSrcEl.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text/html');
  }

  started = false;
  return false;
}

const items = document.querySelectorAll('.dnd__element');
items.forEach(function(item) {
  item.classList.remove(
    'dnd__element--dragStart',
    'dnd__element--dragEnd',
    'dnd__element--dragOver'
  );
  item.addEventListener('dragstart', handleDragStart, false);
  item.addEventListener('dragover', handleDragOver, false);
  item.addEventListener('dragenter', handleDragEnter, false);
  item.addEventListener('dragleave', handleDragLeave, false);
  item.addEventListener('drop', handleDrop, false);
  item.addEventListener('dragend', handleDragEnd, false);
});
.dnd__element {
  cursor: move;
  border: 3px solid #777;
  background-color: #ddd;
  padding: 1rem;
  border-radius: 0.5rem;
  float: left;
}

.dnd__element--dragStart {
  opacity: 0.4;
}

.dnd__element--dragEnd {
  opacity: 1;
}

.dnd__element--dragOver {
  border: 3px dotted #666;
}

.dnd__drag-zone {
  height: 20rem;
  background-color: cornsilk;
}

.heading-tertiary {
  display: block;
  background-color: darkkhaki;
  padding: 2rem 1rem;
}
<section class="section-dnd">
    <div class="dnd__drag-zone">
        <h3 class="heading-tertiary">Drag zone</h3>
        <div class="dnd__element dnd__element--dragStart" id="d1" draggable="true">
            Box 1
        </div>
        <div class="dnd__element dnd__element--dragEnd" id="d2" draggable="true">
            Box 2
        </div>
        <div class="dnd__element dnd__element--dragOver" draggable="true">
            Box 3
        </div>
    </div>
</section>