1. HTML5 drag-and-drop API
The drag and drop API allows you to drag and drop web content. With the help of the drag and drop API, we can achieve some practical functions, such as drag and drop file upload, puzzle games. Let’s start with basic drag-and-drop knowledge and drag-and-drop events
2. Drag and drop
Any element in the browser can be a drag target by default, but if you drag a target directly, the mouse becomes “disabled” because the drag target must be placed in a release zone. Simply put, in order for drag-and-drop to work, there must be a destination for dragging and a release area for dragging. When an element is dragged, three events are triggered
- Drapstart (triggered when dragging starts, with mouse down)
- Drap (triggers repeatedly as you drag)
- Dragend (triggered when dragging is over, mouse release)
So how do you create a free zone? You create a free zone by binding the first two events
- Dragenter (triggered by dragging the target into the release zone)
- Dragover (triggered when the target of the drag moves in the release area)
- Drapleave (Drag the target away from the release zone)
- Drop (triggered when the dragging target is released from the release zone, i.e. the mouse is released from the release zone)
3. Implement basic drag and drop
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
<style>
#src > * {
float: left;
}
#src img{
width: 100px;
border: thin solid black;
margin: 0 15px;
}
#target{
width: 102px;
height: 102px;
border: thin solid black;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
}
#target p{
margin: 0;
text-align: center;
}
#target img{
border: none;
margin: 0;
}
img.dragged{
background-color: darkcyan;
opacity:.5;
}
</style>
</head>
<body>
<div id="src">
<! -- The draggable attribute can be left unset, the default value is auto, and all elements can be dragged by default -->
<img src="./img/apple.jpg" id="apple" alt="">
<img src="./img/banana.jpg" id="banana" alt="">
<img src="./img/cherry.jpg" id="cherry" alt="">
<div id="target" draggable="false">
<span>Drop Here</span>
</div>
</div>
<script>
let src = document.getElementById('src')
let target = document.getElementById('target')
let msg = document.querySelector('#target span')
// Drag the object
src.addEventListener('dragstart'.function(e) {
})
src.addEventListener('dragend'.function(e) {
msg.innerHTML = 'Drop Here'
})
src.addEventListener('drag'.function(e) {
msg.innerHTML = e.target.id
})
// Create a free zone
target.addEventListener('dragenter'.function(e) {
e.preventDefault()
})
target.addEventListener('dragover'.function(e) {
e.preventDefault()
})
</script>
</body>
</html>
Copy the code
You can see that we’ve implemented a simple drag and drop, drag the fruit image into the release area, which means that the release area has been created,Note here that the default behavior of dragenter and dragover events is to refuse to accept any drag-and-drop items, so use event objects to prevent the default behavior.
4. Drag and drop
Through the above code, to achieve a basic drag and drop, the next implementation of a complete case. Basically what it does is drag an image to the release area. Ideas:
- Start by creating a release area for the drag object binding event
- When the fruit is dragged, the release area shows the id of the fruit
- When the fruit is dragged to the release area, a clone of the picture is displayed in the release area
Attach the full code:
let src = document.getElementById('src')
let target = document.getElementById('target')
let msg = document.querySelector('#target span')
let dragged = null
src.addEventListener('dragstart'.function(e) {
dragged = e.target
e.target.classList.add('dragged')
})
src.addEventListener('dragend'.function(e) {
msg.innerHTML = 'Drop Here'
//
Array.from(document.querySelectorAll('.dragged'), function(item) {
item.classList.remove('dragged')
})
})
src.addEventListener('drag'.function(e) {
msg.innerHTML = e.target.id
})
Dragenter and dragover do not accept any drag-drop items by default, so you need to prevent the default behavior
target.addEventListener('dragenter'.function(e) {
e.preventDefault()
})
target.addEventListener('dragover'.function(e) {
e.preventDefault()
})
target.addEventListener('dragleave'.function(e) {
})
target.addEventListener('drop'.function(e) {
this.innerHTML = ' '
msg.innerHTML = ' '
this.append(dragged.cloneNode(false))})Copy the code
The end result:
5. Drag and drop and file upload
The drag and drop API is often used for dragging files from the local desktop to a web page for uploading. The basic idea is the same as in the previous case, except that the XMLHttpRequest object is used to upload the user-selected file to the server.
5.1 DataTransfer object
The first step in implementing drag-and-drop file uploadings is to think about how to get the file that the user is dragging. This is where the DataTransfer object comes in. The DataTransfer object is an object that is dispatched when the drag-and-drop event is triggered. This object contains some useful properties and methods, including the Files property, which holds the list of files generated during the drag.
5.2. Concrete implementation
file.js:
function post(url, data) {
return new Promise(function(resolve, reject) {
const xhr = new XMLHttpRequest()
xhr.addEventListener('readystatechange'.function() {
if(xhr.readyState === 4) {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
resolve(JSON.parse(xhr.responseText))
}
}
})
xhr.open('post', url, true)
// Set the timeout period
xhr.timeout = 1000
xhr.addEventListener('timeout'.function() {
throw new Error('Request timed out! ')
})
xhr.send(data)
})
}
export default class XDfile{
static defaultOptions = {
// File release area
target: document.body || document.documentElement.body,
// Click to check whether the file dialog box can be displayed
clickAddFile: true.// Upload path
uploadUrl: ' '.// File into the release area of the added class
dragenterCls: 'dragged'.False: multiple files can be added at a time. False: multiple files cannot be added at a time
multiple: true.// Limit the file type
accept: The '*'.// The file is automatically uploaded after being added
autoUpload: false.// The callback function after the file is added. The argument is the list of files that were added
addFiles: function(){},
// The callback function after the upload operation is complete. The argument is the list of results returned by the server
uploaded: function(){}}constructor(options) {
// Merge configuration objects
this.options = Object.assign(XDfile.defaultOptions, options)
this.init()
}
init() {
// File list
this.fileLists = []
// Add a file control
if(this.options.clickAddFile) {
this.file = document.createElement('input')
this.file.type = 'file'
this.file.accept = this.options.accept
this.file.style.display = 'none'
this.file.multiple = this.options.multiple
this.options.target.appendChild(this.file)
// Click on the drag and drop area, equivalent to clicking on the Input file control
this.options.target.addEventListener('click'.() = > {
this.file.click()
})
// Bind the change event
this.file.addEventListener('change'.(e) = > {
// Upload the file
this.options.autoUpload && this.upload(e.target.files)
this.fileLists.push(... e.target.files)this.options.addFiles(e.target.files)
})
}
const _this = this
// Initialize the drag-and-drop release area
this.options.target.addEventListener('dragenter'.function(e) {
e.preventDefault()
})
this.options.target.addEventListener('dragleave'.function(e) {
_this.options.target.classList.remove(_this.options.dragenterCls)
})
this.options.target.addEventListener('dragover'.function(e) {
e.preventDefault()
_this.options.target.classList.add(_this.options.dragenterCls)
})
this.options.target.addEventListener('drop'.function(e) {
// The operation when the user adds the file
e.preventDefault()
_this.options.target.classList.remove(_this.options.dragenterCls)
let files = e.dataTransfer.files
if(! _this.options.multiple && files.length >1) {
// Only one file can be added at a time
console.warn('[XDfile Warn]: Only upload or add one file at a time (single file limit)')
return
}
// Upload the file_this.options.autoUpload && _this.upload(files) _this.fileLists.push(... files) _this.options.addFiles(files) }) }upload(files) {
const tasks = []
for(const file of files) {
const data = new FormData()
data.append('file', file)
data.append('model'.'user')
data.append('project'.'mos')
data.append('user'.'admin')
tasks.push(post(this.options.uploadUrl, data))
}
Promise.all(tasks).then((res) = > {
this.options.uploaded(res)
})
}
}
Copy the code
file.html:
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
<link rel="stylesheet" href="css/iconfont.css">
<link rel="stylesheet" type="text/css" href="css/index.css"/>
</head>
<body>
<ul class="file-list">
</ul>
<div id="file_target">
<i class="iconfont icon-yunpanlogo-3"></i>
<p class="">Drag and drop the file here</p>
</div>
<div class="upload-info">
</div>
<script type="module">
import XDfile from './js/file.js'
let xdfile = new XDfile({
target: document.getElementById('file_target'),
addFiles: handleAddFiles,
multiple: true.uploadUrl: 'http://localhost:8081/MoFiles/public/upload.php'.uploaded: handleUploaded,
progress: function(data) {
console.log(data)
},
autoUpload: true.accept: 'image/*'
})
function handleAddFiles(files) { fileList.push(... files)const list = document.querySelector('.file-list')
let html = ' '
Array.from(files, file= > {
html += template(file)
})
list.innerHTML += html
}
function handleUploaded(res) {
const info = document.querySelector('.upload-info')
let html = ' '
for(let info of res) {
html += ` < p > file"${info.name}</p> '
}
info.innerHTML += html
}
function template(file) {
let html = ' '
if(file.type.split('/') [0= = ='image') {let bloburl = URL.createObjectURL(file)
html = `
<li class="flie-item" style="background-image:url(${bloburl})" title="${file.name}">
<span class="file-name">${file.name}</span>
</li>
`
} else {
html = `
<li class="flie-item" style="background-image:url(./img/file.png)" title="${file.name}">
<span class="file-name">${file.name}</span>
</li>
`
}
return html
}
</script>
</body>
</html>
Copy the code
The end result:
5.3. Code analysis
File.js implements a simple file upload class that initializes drag-and-drop areas and uploads after adding files. This class supports user drag-and-drop uploads and file dialog uploads. Supports adding a single file and multiple files. The init() method does some initialization based on the configuration object generation (initializing the drag-and-drop area and whether the file can be added through the file dialog box, and the user calls the corresponding callback function after adding the file), and the upload() method uploadthe file. File.html Import the XDfile class and pass in the corresponding configuration items
6. References
Advanced Programming in JavaScript (third edition) The definitive guide to HTML