block by boeric deb4dfb7bc6f1f9e9a5b3bdd4ad2cc2c

Drag and Drop Using Native DOM Methods

Full Screen

Drag and Drop

Demo of drag and drop using only native DOM methods.

Usage: Grab one of the randomly generated elements and drag it around the four droppable zones. When when the drag is complete, the item will be appended to the “destination” zone.

The demo shows simple uses of:

index.js

/* By Bo Ericsson, https://www.linkedin.com/in/boeric00/ */

/* eslint-disable func-names, wrap-iife, no-plusplus, no-param-reassign, no-bitwise */

// Id generator (a demo of iife, generator function, and closure)
// Outer iife to define the getId function, which returns an ever increasing integer
// with each call
const getId = (() => {
  // Inner iife to run the generator function which returns 'id', a generator object
  const id = (function* () {
    let i = 0;
    while (true) {
      yield i++;
    }
  })();

  // The 'id' generator is locked inside the outer iife's closure
  return () => id.next().value;
})();

// Returns an array of specified size with values incrementing from 0
function range(length) {
  const array = [];
  for (let i = 0; i < length; i++) {
    array.push(i);
  }
  return array;
}

// Zone colors (used to pick colors for the object generated in each zone)
const zoneColors = ['blue', 'green', 'orange', 'darkred'];

// Obtain references to the four zones
const zones = document.querySelectorAll('.zone');

// Drag handlers
let source; // Contains a reference to the item being dragged

// Triggers when an item starts being dragged
function ondragstart(evt) {
  // Add the 'dragging' class from the item being moved
  this.classList.add('dragging');
  // Save a reference to the item being dragged
  source = this;
  evt.dataTransfer.effectAllowed = 'move';
}

function ondragover(evt) {
  evt.preventDefault();
}

function ondragenter(evt) {
  if (evt.target.classList.contains('zone')) {
    // Add the 'droppable' class of the zone element
    evt.target.classList.add('droppable');
  }
  evt.preventDefault();
}

function ondragleave(evt) {
  if (evt.target.classList.contains('zone')) {
    // Remove the 'droppable' class of the zone element
    evt.target.classList.remove('droppable');
  }
}

function ondrop(evt) {
  // Remove the 'dragging' class from the item being moved
  source.classList.remove('dragging');

  if (evt.target.classList.contains('zone')) {
    // Remove the 'droppable' class of the zone element
    evt.target.classList.remove('droppable');
    // Move the item
    evt.target.appendChild(source);
  }
  evt.preventDefault();
}

// Create items
zones.forEach((zone, zoneIdx) => {
  // Add handlers for the zone's drag events
  zone.ondragenter = ondragenter;
  zone.ondragover = ondragover;
  zone.ondragleave = ondragleave;
  zone.ondrop = ondrop;

  // Determine items to create in this zone (min 1, max 7)
  const items = ~~(Math.random() * 7) + 1;

  range(items).forEach((idx) => {
    // Create the element
    const elem = document.createElement('div');
    // Generate the text for the element
    const text = `${zoneIdx}-${idx}`;
    elem.innerHTML = text;
    // Determine type (circle or square randomly)
    const type = Math.random() > 0.5 ? 'circle' : 'square';
    elem.className = `item ${type} color-${zoneColors[zoneIdx]}`;
    // Set the element id (not necessary but demos, when inspected,
    // that items actually move, not just the innerHTML)
    elem.id = getId();
    // Enable dragging
    elem.draggable = true;
    // Handler to kickstart the dragging process
    elem.ondragstart = ondragstart;

    // Append the item to the zone
    zone.appendChild(elem);
  });
});

index.html

<!doctype html>

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Drag and Drop Demo</title>
  <link rel="stylesheet" href="styles.css">
  <script src="index.js" defer></script>
</head>
<body>
  <div class="row">
    <div id="zone-0" class="zone"></div>
    <div id="zone-1" class="zone"></div>
  </div>
  <div class="row">
    <div id="zone-2" class="zone"></div>
    <div id="zone-3" class="zone"></div>
  </div>
</body>
</html>

styles.css

body {
  width: 940px;
  max-width: 940px;
  height: 480px;
  max-height: 480px;
  margin: 10px;
  outline: 1px solid gray;
  font-family: arial;
}
.row {
  display: flex;
  flex-direction: row;
}
.zone {
  width: 470px;
  height: 240px;
  outline: 1px solid lightgray;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  overflow: scroll;
}
.item {
  margin: 10px;
  color: white;
  text-align: center;
  line-height: 75px;
}
.circle {
  width: 75px;
  height: 75px;
  border-radius: 50%;
  background-color: blue;
}
.square {
  width: 75px;
  height: 75px;
  background-color: green;
}
.color-blue {
  background-color: blue;
}
.color-green {
  background-color: green;
}
.color-orange {
  background-color: orange;
}
.color-darkred {
  background-color: darkred;
}
.dragging {
  background-color: rgba(150, 150, 150, 0.7);
}
.droppable {
  background-color: rgba(150, 150, 150, 0.2);
}