如何检测拖动的元素是否被拖放到其父元素之外?

How to detect if a dragged element is dropped outside of its parent?

我想了解何时将元素拖放到其父元素之外:

element.addEventListener('dragend', function(event) {
  // check if element is dropped outside its parent
}, false)

此技术通过以下方式识别拖动的元素是否被放入其父元素中:

  1. 在 'dragstart'
  2. 上存储 dragParent 元素
  3. 添加 'drop' 事件监听器到 window
  4. 使用掉落事件的 event.target 确定掉落目标
  5. 沿着事件目标的 DOM 树搜索 dragParent

// the parent of the dragged element
let dragParent = null;

function handleDragstart(ev) {
  // record the dragged element's parent
  dragParent = ev.target.parentElement;

  // set a 'drop' listener to the window
  window.addEventListener('drop', handleDrop);
}

// handle a 'drop' event to the window
function handleDrop(ev) {
  ev.preventDefault();

  // remove the 'drop' listener
  window.removeEventListener('drop', handleDrop);

  // search up target's DOM tree for dragParent
  for (let el = ev.target; el.tagName !== 'HTML'; el = el.parentElement) {
    if (el === dragParent) {
      alert('#p1 was dropped inside dragParent');
      return;
    }
  }
  alert('#p1 was dropped outside dragParent');
}

// these event handers are required to make an element into a drop zone
function handleDragover(ev) {
  ev.preventDefault();
}

function handleDragend(ev) {}

// convert some elements into drop zones
// ref: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API#define_a_drop_zone
//
function makeDropZone(el) {
  el.addEventListener('dragover', handleDragover);
  el.addEventListener('drop', handleDragend);
}
for (const elId of ['sibling', 'parent', 'stranger']) {
  const element = document.getElementById(elId);
  makeDropZone(element);
}
makeDropZone(document.body);

// make `#p1` draggable
document.getElementById('p1').addEventListener('dragstart', handleDragstart);
body {
  padding: 0.4rem 0 2rem 0.4rem;
  height: calc(100% - 0.5rem);
  width: calc(100% - 2rem);
  border: 1px solid #888;
  font-family: sans-serif;
}

div {
  padding: 0.6rem;
}

#parent {
  background-color: #ddd;
  width: 90%;
  padding: 0.3rem;
}

#p1 {
  background-color: white;
  padding: 0.1rem;
  width: 30%;
}

#sibling {
  background-color: #bbb;
  width: 50%;
  height: 3rem;
}

#stranger {
  background-color: #ddd;
  margin: 0.5rem 0;
  width: 90%;
  height: 80px;
  padding: 0.3rem;
}
<body>
  body
  <h3>Drag <code>#p1</code> onto <code>#sibling</code>, <code>#parent</code>, or
    <code>body</code></h3>
  <div id="parent">
    #parent
    <p id="p1" draggable="true">
      #p1 (draggable)
    </p>
    <div id="sibling">
      #sibling
    </div>
  </div>
  <div id="stranger">
    #stranger
  </div>
</body>