前言
本文主要讲述基于 HTML5 的拖放(Drag and Drop)API 实现的简单拖拽功能,代码和思路如下
废话少说 直接上效果
Let's show you the code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>拖拽demo</title>
<style>
body {
display: flex;
}
.box1,
.box2 {
width: 300px;
height: 600px;
border: 1px solid rgb(250, 10, 10);
}
.box2 {
margin-left: 50px;
}
.item {
width: 100px;
height: 50px;
display: flex;
border-radius: 50%;
justify-content: center;
align-items: center;
background-color: rgb(135, 235, 140);
margin-top: 10px;
margin-left: 10px;
}
</style>
</head>
<body>
<div class="box1">
<div class="item" draggable="true" ondragstart="dragStart(event,'阿里')">
阿里
</div>
<div class="item" draggable="true" ondragstart="dragStart(event,'腾讯')">
腾讯
</div>
<div class="item" draggable="true" ondragstart="dragStart(event,'字节')">
字节
</div>
<div class="item" draggable="true" ondragstart="dragStart(event,'滴滴')">
滴滴
</div>
</div>
<div
class="box2"
ondrop="dropEnd(event)"
></div>
</body>
<script>
const box2 = document.querySelector('.box2')
function dragStart(e, device) {
e.dataTransfer.setData('device', device)
}
function dropEnd(e) {
var transferredDevice = e.dataTransfer.getData('device')
const div = document.createElement('div')
div.textContent = transferredDevice
div.classList.add('item')
box2.appendChild(div)
}
// 添加拖拽进入和离开的视觉反馈
box2.addEventListener('dragover', function(e) {
e.preventDefault(); // 允许放置
box2.classList.add('over');
});
box2.addEventListener('dragleave', function() {
box2.classList.remove('over');
});
</script>
</html>
实现思路
-
设置可拖拽元素:
- 使用
draggable="true"属性来标记一个元素是可拖拽的。通过给每个div.item元素添加draggable="true"实现的。
- 使用
-
开始拖拽(
dragstart事件) :- 当用户开始拖动一个元素时,会触发
dragstart事件。 - 在
dragstart事件的处理函数中,可以使用event.dataTransfer.setData()方法来设置需要传递的数据。这里的数据是被拖动元素的标识或其他相关信息。
- 当用户开始拖动一个元素时,会触发
-
允许放置(
dragover事件) :- 默认情况下,无法将元素放置到其他元素上。为了允许放置,需要阻止
dragover事件的默认行为。 - 在
dragover事件的处理函数中调用event.preventDefault()方法,可以允许元素被放置。
- 默认情况下,无法将元素放置到其他元素上。为了允许放置,需要阻止
-
处理放置(
drop事件) :- 当拖拽的元素被放置到目标区域时,会触发
drop事件。 - 在
drop事件的处理函数中,可以使用event.dataTransfer.getData()方法来获取之前设置的数据。 - 然后,可以根据获取的数据执行相关操作,如在目标区域创建新元素或移动原始元素。
- 当拖拽的元素被放置到目标区域时,会触发
-
结束拖拽(
dragend事件) :- 当拖拽操作完成(无论是成功放置还是取消)时,会触发
dragend事件。 - 可以在
dragend事件的处理函数中执行一些清理工作。
- 当拖拽操作完成(无论是成功放置还是取消)时,会触发
接下来尝试下左右互相拖拽的感觉
直接看效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>拖拽demo</title>
<style>
body {
display: flex;
}
.box1, .box2 {
width: 300px;
height: 600px;
border: 1px solid rgb(250, 10, 10);
padding: 10px;
}
.box2 {
margin-left: 50px;
}
.item {
width: 100px;
height: 50px;
display: flex;
border-radius: 50%;
justify-content: center;
align-items: center;
background-color: rgb(135, 235, 140);
margin-bottom: 10px;
cursor: pointer; /* 添加手指指针样式 */
}
.over {
border: 2px dashed #000; /* 当拖拽元素进入时,显示虚线边框 */
}
</style>
</head>
<body>
<div class="box1" ondrop="drop(event)" ondragover="allowDrop(event)">
<div class="item" draggable="true" id="item1">阿里</div>
<div class="item" draggable="true" id="item2">腾讯</div>
<div class="item" draggable="true" id="item3">字节</div>
<div class="item" draggable="true" id="item4">滴滴</div>
</div>
<div class="box2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<script>
function dragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id);
}
function drop(e) {
e.preventDefault();
var data = e.dataTransfer.getData('text/plain');
var draggedElement = document.getElementById(data);
e.target.appendChild(draggedElement);
}
function allowDrop(e) {
e.preventDefault();
if (e.target.className === "box1" || e.target.className === "box2") {
e.target.classList.add('over');
}
}
// 给所有可拖拽的元素添加事件监听
document.querySelectorAll('.item').forEach(item => {
item.addEventListener('dragstart', dragStart);
});
// 给 box1 和 box2 添加 dragleave 事件监听
document.querySelectorAll('.box1, .box2').forEach(box => {
box.addEventListener('dragleave', function(e) {
if (e.target.className === "box1" || e.target.className === "box2") {
e.target.classList.remove('over');
}
});
});
</script>
</body>
</html>
具体思路
- 设置元素为可拖拽
- 为每个需要拖拽的元素设置
draggable="true"属性。 - 为这些元素添加一个唯一的
id,以便在拖拽过程中识别它们。
- 捕获拖拽开始的事件
- 为所有可拖拽的元素添加
dragstart事件监听器。 - 在
dragstart事件的处理函数中,使用event.dataTransfer.setData()方法存储被拖拽元素的id。
- 允许在目标容器上放置
- 为目标容器(在这个案例中是
box1和box2)添加dragover事件监听器。 - 在
dragover事件的处理函数中,调用event.preventDefault()方法来阻止默认行为,从而允许在这些容器上放置元素。
- 处理元素放置
- 为目标容器添加
drop事件监听器。 - 在
drop事件的处理函数中,使用event.dataTransfer.getData()方法获取被拖拽元素的id。 - 使用
document.getElementById()获取被拖拽的元素,并将其追加到触发drop事件的容器中。由于appendChild方法实际上是移动元素,所以被拖拽的元素会从原来的位置移动到新位置,从而实现了删除原来元素的效果。
- 添加视觉反馈
- 在
dragover和dragleave事件中,可以通过添加或移除 CSS 类来为用户提供视觉反馈,比如改变容器的边框样式。