概要:在本教程中,您将了解 JavaScript 拖放 API 以及如何使用它来实现一个简单的拖放应用程序。
JavaScript 拖放 API 简介
HTML5 正式引入了拖放规范。大多数现代 Web 浏览器都实现了基于 HTML5 规范的原生拖放功能。
默认情况下,只有图像和文本可以拖放。要拖放图像,您只需按住鼠标按钮,然后移动它。要拖放文本,您需要突出显示一些文本,并像拖放图像一样拖放它。
HTML5 规范指定几乎所有元素都可以拖放。要使元素可拖放,您需要将draggable
属性及其值为true
添加到其 HTML 标签中。例如
<div class="item" draggable="true"></div>
Code language: HTML, XML (xml)
可拖放元素上的事件
当您拖放元素时,这些事件将按以下顺序触发
dragstart
drag
dragend
当您按住鼠标按钮并开始移动鼠标时,dragstart
事件将在您拖动的可拖放元素上触发。光标将更改为禁止拖放符号(带有斜线的圆圈),以指示您无法将元素拖放到自身上。
dragstart
事件触发后,只要您拖动元素,drag
事件就会反复触发。
dragend
事件在您停止拖动元素时触发。
所有事件的目标(e.target
)都是正在拖动的元素。
默认情况下,浏览器不会更改拖动元素的外观。因此,您可以根据自己的喜好自定义其外观。
放置目标上的事件
当您将元素拖放到有效的放置目标上时,这些事件将按以下顺序触发
dragenter
dragover
dragleave
或drop
当您将元素拖放到放置目标上时,dragenter
事件就会触发。
dragenter
事件触发后,只要您拖动元素在放置目标的边界内,dragover
事件就会反复触发。
当您将元素拖出放置目标的边界时,dragover
事件将停止触发,dragleave
事件将触发。
如果您将元素放置到目标上,则drop
事件将触发,而不是dragleave
事件。
dragenter
、dragover
、dragleave
和 drop
事件的目标(e.target
)是放置目标元素。
有效的放置目标
几乎所有元素都支持放置目标事件(dragenter
、dragover
、dragleave
和 drop
)。但是,它们默认不允许放置。
如果您将元素拖放到不允许放置的放置目标上,则drop
事件将不会触发。
要将元素变成有效的放置目标,您可以通过在相应的事件处理程序中调用event.preventDefault()
方法来覆盖dragenter
和dragover
事件的默认行为。(有关更多信息,请参阅示例部分)
使用 dataTransfer 对象传输数据
要传输拖放操作中的数据,您需要使用dataTransfer
对象。
dataTransfer
对象是事件的一个属性。它允许您将数据从拖动的元素传输到放置目标。
dataTransfer
对象有两种方法:setData()
和 getData()
。
setData()
允许您将拖动操作的数据设置为指定的格式和数据
dataTransfer.setData(format, data)
Code language: CSS (css)
格式可以是text/plain
或 text/uri-list
。数据可以是表示要添加到拖动对象的字符串。
getData()
方法检索由 setData()
方法存储的拖动数据。
getData()
接受一个参数
dataTransfer(format)
格式可以是text/plain
或 text/uri-list
。getData()
返回由 setData()
方法存储的字符串,或者如果拖动操作不包含数据,则返回空字符串。
JavaScript 拖放示例
我们将开发以下简单的拖放应用程序 来演示 JavaScript 拖放 API
创建项目结构
首先,创建一个名为drag-n-drop-basics
的新文件夹。在这个文件夹中,创建两个子文件夹,分别称为css
和 js
。
其次,在 js
文件夹中创建一个名为 app.js
的新文件,在 css
文件夹中创建一个名为 style.css
的文件,并在 drag-n-drop-basics
文件夹中创建一个名为 index.html
的文件。
第三,将指向style.css
的链接和指向 app.js
的脚本标签放在 index.html
文件中,如下所示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript - Drag and Drop Demo</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script src="js/app.js"></script>
</body>
</html>
Code language: HTML, XML (xml)
对于 CSS,您可以从此处获取。
构建 index.html 文件
将以下代码放在 index.html
文件中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript - Drag and Drop Demo</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<h1>JavaScript - Drag and Drop</h1>
<div class="drop-targets">
<div class="box">
<div class="item" id="item">
</div>
</div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
<script src="js/app.js"></script>
</body>
</html>
Code language: HTML, XML (xml)
在这个 index.html 文件中,我们使用了 .container
元素来对齐标题和 drop-targets
元素。
在 drop-targets 元素中,我们放置了三个具有相同类 box
的 div
元素。我们还在第一个盒子中放置了另一个具有类 item
的 div 元素。
如果您打开 index.html
并尝试拖动黄色方块,您会看到光标指示您无法拖动。

要使元素可拖放,您需要将draggable
属性及其值为true
添加到其 HTML 标签中,如下所示
<div class="item" id="item" draggable="true">
Code language: JavaScript (javascript)
现在,如果您保存 index.html
,在浏览器中再次打开它,您会看到您可以拖动 item 元素,如下所示

处理可拖放元素上的事件
style.css
文件具有.hide
类,该类可以隐藏元素。
.hide {
display: none;
}
Code language: CSS (css)
在 app.js
文件中,您需要添加以下代码
// select the item element
const item = document.querySelector('.item');
// attach the dragstart event handler
item.addEventListener('dragstart', dragStart);
// handle the dragstart
function dragStart(e) {
console.log('drag starts...');
}
Code language: JavaScript (javascript)
工作原理
- 首先,使用
querySelector()
选择可拖放元素。 - 其次,将
dragstart
事件处理程序附加到可拖放元素。 - 第三,定义
dragStart()
函数来处理dragstart
事件。
如果您打开 index.html 文件并开始拖动可拖放元素,您会在控制台中看到 drag starts...
消息。
在 dragStart
事件处理程序中,您需要存储可拖放元素的id
。您还需要隐藏它。
function dragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id);
e.target.classList.add('hide');
}
Code language: JavaScript (javascript)
如果您拖动元素,您会看到它在您开始拖动时会消失。
要解决此问题,您可以使用 setTimeout()
函数
function dragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id);
setTimeout(() => {
e.target.classList.add('hide');
}, 0);
}
Code language: JavaScript (javascript)
现在,您可以将可拖放元素拖出其原始位置。

处理放置目标上的事件
style.css
文件还有一个名为 .drag-over
的 CSS 类,该类可以将放置目标的边框样式更改为虚线红色。
.drag-over {
border: dashed 3px red;
}
Code language: CSS (css)
在 app.js 中,您需要选择放置目标元素,并处理这些元素的 dragenter
、dragover
、dragleave
和 drop
事件。
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
box.addEventListener('dragenter', dragEnter)
box.addEventListener('dragover', dragOver);
box.addEventListener('dragleave', dragLeave);
box.addEventListener('drop', drop);
});
function dragEnter(e) {
}
function dragOver(e) {
}
function dragLeave(e) {
}
function drop(e) {
}
Code language: JavaScript (javascript)
放置目标的边框样式应在 dragenter
和 dragover
事件发生时更改。在 dragleave
和 drop
事件发生时,它应恢复样式。
为此,您需要向放置目标添加和删除 drag-over
类,如下所示
function dragEnter(e) {
e.target.classList.add('drag-over');
}
function dragOver(e) {
e.target.classList.add('drag-over');
}
function dragLeave(e) {
e.target.classList.remove('drag-over');
}
function drop(e) {
e.target.classList.remove('drag-over');
}
Code language: JavaScript (javascript)
现在,如果您将可拖放元素拖放到另一个放置目标,您会看到放置目标的边框会发生变化,如下面的图片所示。

要使放置目标有效,您需要在 dragenter
和 dragover
事件处理程序中调用 event.preventDefault()
,如下所示
function dragEnter(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}
function dragOver(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}
Code language: JavaScript (javascript)
如果您不这样做,drop
事件将永远不会触发,因为 div
元素默认不是有效的放置目标。
如果您将可拖放元素拖放到放置目标,您会看到光标会发生变化,表示您可以放置元素。

现在,如果您放置 item 元素,您会看到它会立即消失。
要解决此问题,您需要添加对 drop
事件的处理。
- 首先,使用
dataTransfer
对象的getData()
方法获取可拖放元素的id
。 - 其次,将可拖放元素作为子元素附加到放置目标元素。
- 第三,从可拖放元素中删除
hide
类。
以下代码显示了完整的 drop
事件处理程序
function drop(e) {
e.target.classList.remove('drag-over');
// get the draggable element
const id = e.dataTransfer.getData('text/plain');
const draggable = document.getElementById(id);
// add it to the drop target
e.target.appendChild(draggable);
// display the draggable element
draggable.classList.remove('hide');
}
Code language: JavaScript (javascript)
如果您现在拖放可拖放元素,它应该按预期工作。
以下是完整的 app.js 文件
/* draggable element */
const item = document.querySelector('.item');
item.addEventListener('dragstart', dragStart);
function dragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id);
setTimeout(() => {
e.target.classList.add('hide');
}, 0);
}
/* drop targets */
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
box.addEventListener('dragenter', dragEnter)
box.addEventListener('dragover', dragOver);
box.addEventListener('dragleave', dragLeave);
box.addEventListener('drop', drop);
});
function dragEnter(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}
function dragOver(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}
function dragLeave(e) {
e.target.classList.remove('drag-over');
}
function drop(e) {
e.target.classList.remove('drag-over');
// get the draggable element
const id = e.dataTransfer.getData('text/plain');
const draggable = document.getElementById(id);
// add it to the drop target
e.target.appendChild(draggable);
// display the draggable element
draggable.classList.remove('hide');
}
Code language: JavaScript (javascript)
以及演示的链接。
概要
- 将
draggable
属性及其值为 true 添加到元素,以使其可拖放。 dragstart
、drag
和dragend
事件将在可拖放元素上触发。dragenter
、dragover
、dragleave
或drop
事件将在放置目标上触发。- 在
dragenter
和dragover
事件处理程序上调用event.preventDefault()
,以使元素成为有效的放置目标。 - 使用
event.dataTransfer
对象及其setData()
和getData()
方法在拖放操作中传输数据。