Skip to content

Instantly share code, notes, and snippets.

@boeric
Last active May 23, 2020 19:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boeric/deb4dfb7bc6f1f9e9a5b3bdd4ad2cc2c to your computer and use it in GitHub Desktop.
Save boeric/deb4dfb7bc6f1f9e9a5b3bdd4ad2cc2c to your computer and use it in GitHub Desktop.
Drag and Drop Using Native DOM Methods

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:

<!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>
/* 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);
});
});
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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment