HTML5 提供了原生的拖拽(Drag and Drop)API,允许元素在页面内或不同页面间进行拖拽交互。核心事件包括 dragstart
、dragover
、drop
等。
一、基本概念
拖拽操作涉及两个角色:
- 被拖拽元素(源元素):用户拖动的元素
- 目标元素:接收被拖拽元素的区域
二、核心事件
事件名称 | 触发时机 | 作用对象 |
---|---|---|
dragstart |
当用户开始拖拽元素时触发 | 被拖拽元素 |
drag |
拖拽过程中持续触发 | 被拖拽元素 |
dragend |
拖拽结束时触发(无论成功与否) | 被拖拽元素 |
dragenter |
被拖拽元素进入目标区域时触发 | 目标元素 |
dragover |
被拖拽元素在目标区域内移动时触发 | 目标元素 |
dragleave |
被拖拽元素离开目标区域时触发 | 目标元素 |
drop |
被拖拽元素在目标区域释放时触发 | 目标元素 |
三、实现步骤
1. 使元素可拖拽
默认情况下,只有部分元素(如图片、链接)可拖拽。其他元素需设置 draggable="true"
属性:
<div draggable="true" id="draggable">可拖拽元素</div>
2. 监听拖拽事件
// 被拖拽元素
const draggable = document.getElementById('draggable');
// 目标区域
const dropZone = document.getElementById('dropZone');// 1. 开始拖拽时触发
draggable.addEventListener('dragstart', (e) => {// 设置拖拽数据(可传递文本、URL等)e.dataTransfer.setData('text/plain', draggable.id);// 可选:设置拖拽时的视觉效果e.dataTransfer.effectAllowed = 'move';
});// 2. 拖拽结束时触发
draggable.addEventListener('dragend', (e) => {console.log('拖拽结束');
});// 3. 当元素进入目标区域时
dropZone.addEventListener('dragenter', (e) => {e.preventDefault(); // 允许进入dropZone.classList.add('highlight'); // 视觉反馈
});// 4. 当元素在目标区域内移动时(必须阻止默认行为,否则无法触发drop)
dropZone.addEventListener('dragover', (e) => {e.preventDefault(); // 关键:允许放置e.dataTransfer.dropEffect = 'move';
});// 5. 当元素离开目标区域时
dropZone.addEventListener('dragleave', () => {dropZone.classList.remove('highlight');
});// 6. 当元素在目标区域释放时(核心:处理放置逻辑)
dropZone.addEventListener('drop', (e) => {e.preventDefault();dropZone.classList.remove('highlight');// 获取拖拽数据const draggedId = e.dataTransfer.getData('text/plain');const draggedElement = document.getElementById(draggedId);// 执行放置操作(例如移动元素)dropZone.appendChild(draggedElement);
});
四、关键说明
-
dataTransfer
对象:用于在拖拽过程中传递数据,常用方法:setData(format, data)
:设置数据(格式通常为text/plain
或text/uri-list
)getData(format)
:获取数据
// 拖拽时设置多种格式数据 e.dataTransfer.setData('text/plain', '简单文本'); e.dataTransfer.setData('text/html', '<strong>HTML内容</strong>'); e.dataTransfer.setData('text/uri-list', 'https://example.com');//自定义格式(如application/json)// 放置时获取指定格式数据 const htmlData = e.dataTransfer.getData('text/html');
-
拖拽效果控制
通过
effectAllowed
和dropEffect
控制拖拽行为的视觉提示(鼠标样式会变化):effectAllowed
(在dragstart
中设置):限制允许的操作类型
e.dataTransfer.effectAllowed = 'copy'; // 仅允许复制 // 可选值:none | copy | copyLink | copyMove | link | linkMove | move | all | uninitialized
dropEffect
(在dragover
中设置):指定目标区域接受的操作
e.dataTransfer.dropEffect = 'move'; // 表示移动操作 // 可选值:none | copy | link | move
-
拖拽取消与默认行为:
-
dragover
必须阻止默认行为(e.preventDefault()
),否则drop
事件不会触发 -
drop
也需要阻止默认行为(避免浏览器对数据的默认处理,如打开链接、打开图片) -
拖拽过程中按
Esc
键会触发dragend
并取消操作
-
-
跨窗口 / 跨域拖拽
- 支持在同一浏览器的不同标签页之间拖拽(需处理数据格式兼容性)
- 跨域拖拽时,
dataTransfer
只能传递基本文本格式(如text/plain
),复杂格式会被限制
-
拖拽状态样式
/* 元素被拖拽时的样式 */
#draggable:active {opacity: 0.8;
}/* 目标区域可接受拖拽时的样式 */
#dropZone:drop-active {border-color: green;
}
五、幽灵元素
在 HTML5 原生拖拽(Drag & Drop)中,幽灵元素(ghost image) 是指拖拽过程中跟随鼠标指针移动的半透明元素副本,用于视觉上指示正在拖拽的内容。
它不是真实 DOM 元素,而是浏览器自动生成的临时图像,默认情况下是被拖拽元素的快照。
幽灵元素的特点:
- 自动生成:当触发
dragstart
事件时,浏览器会自动创建被拖拽元素的副本作为幽灵元素 - 半透明效果:默认带有一定透明度(通常 50%),与原元素区分开
- 跟随鼠标:始终位于鼠标指针附近(有微小偏移)
- 临时存在:拖拽结束(
dragend
)后自动消失
自定义幽灵元素
默认幽灵元素可能不符合设计需求,可通过 setDragImage()
方法自定义:
// 为拖拽元素添加dragstart事件
draggable.addEventListener('dragstart', (e) => {// 创建自定义幽灵元素const ghost = document.createElement('div');ghost.textContent = '正在拖拽...';ghost.style.padding = '10px';ghost.style.backgroundColor = '#4285f4';ghost.style.color = 'white';// 必须将元素添加到DOM中(可隐藏)document.body.appendChild(ghost);// 自定义幽灵元素e.dataTransfer.setDragImage(ghost, 20, 20); // 最后两个参数是鼠标相对元素的偏移量// 拖拽结束后移除临时元素setTimeout(() => {document.body.removeChild(ghost);}, 0);
});
注意事项:
- 自定义幽灵元素必须先添加到 DOM 中才能生效(可通过
position: fixed; left: -9999px
隐藏) setDragImage()
第三个和第四个参数控制鼠标在幽灵元素上的位置偏移- 若不自定义,浏览器会使用被拖拽元素的可视化副本作为幽灵元素
幽灵元素的主要作用是提供直观的拖拽视觉反馈,帮助用户理解当前正在拖拽的内容和操作状态。
六、常见应用场景
- 拖拽排序(如任务列表)
- 文件上传(拖拽文件到上传区域)
- 拖放式编辑器
- 看板类应用(如 Trello)
通过原生拖拽 API,可以实现灵活的交互效果,无需依赖外部库,兼容性也较好(支持所有现代浏览器)。