HTML 拖放 API:DataTransfer、文件投放与触屏替代方案
本文目录
HTML Drag and Drop API 适用于桌面拖动排序、文件投放等场景,不是通用触屏手势系统,更不能成为唯一操作方式。点击、按钮或键盘路径必须让用户完成相同任务。
事件流程
源元素设置 draggable="true",在 dragstart 写入 DataTransfer;目标收到 dragenter、dragover、dragleave,放下时收到 drop。必须在合法目标的 dragover 中 preventDefault(),浏览器才会允许放下。dragend 可清理源状态。
<ul id="tasks">
<li draggable="true" data-task-id="task-42">
<button type="button" data-action="move-up">上移</button>
<span>准备发布</span>
</li>
</ul>
<div id="drop-target">移动到此处</div>
const list = document.querySelector('#tasks');
const target = document.querySelector('#drop-target');
list.addEventListener('dragstart', (event) => {
const item = event.target.closest('[data-task-id]');
if (!item || !event.dataTransfer) return;
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData('text/plain', item.dataset.taskId);
});
target.addEventListener('dragover', (event) => {
event.preventDefault();
if (event.dataTransfer) event.dataTransfer.dropEffect = 'move';
});
target.addEventListener('drop', async (event) => {
event.preventDefault();
const id = event.dataTransfer?.getData('text/plain');
if (id) await moveTask(id);
});
拖放数据只放最小必要信息,不要放密码、令牌或完整业务对象。放下时重新检查记录是否存在、目标是否有效和当前用户的权限;客户端 ID 不构成授权证明。
文件投放与安全
系统文件通常从 dataTransfer.files 读取,元素间拖放则使用 getData(),两条路径应分别处理。浏览器给出的 MIME 和扩展名可以伪造。前端校验只用于友好提示;服务端仍要限制体积、检测格式、生成随机存储名、验证权限并限制公开访问。
const zone = document.querySelector('#upload-zone');
zone.addEventListener('dragover', (event) => {
event.preventDefault();
zone.classList.add('is-dragging');
});
zone.addEventListener('dragleave', () => {
zone.classList.remove('is-dragging');
});
zone.addEventListener('drop', (event) => {
event.preventDefault();
zone.classList.remove('is-dragging');
const files = [...(event.dataTransfer?.files || [])];
if (files.length) validateAndUpload(files);
});
留意拖动经过子元素造成 enter/leave 闪烁、窗口外取消、空文件、重复投放、卸载时清理监听和上传失败后的恢复。
触屏和无障碍替代
原生拖放主要针对桌面指针。触屏用户应能点选条目后再点目的位置,或用“上移/下移”和位置选择器完成排序。自定义触摸手势需测试滚动、指针捕获、取消、缩放和辅助技术。WCAG 2.2 的拖动准则要求提供不依赖拖动的单指替代,除非拖动本身不可缺少。可投放状态也不能只用颜色表达。
.drop-zone {
min-height: 5rem;
border: 2px dashed #778899;
}
.drop-zone.is-dragging,
.drop-zone:focus-visible {
border-style: solid;
outline: 3px solid #167d72;
outline-offset: 2px;
}
排序完成后应播报项目新位置;键盘可聚焦并操作,点击方案要能真正完成同一流程,而不是只有视觉按钮。
验收清单
- 桌面测试成功、取消和无效放置,所有临时视觉状态均清理。
- 合法、超限、伪造类型和服务器拒绝的文件都得到明确反馈。
- 触屏与键盘无需拖动即可完成任务,读屏器能获知位置变化。
- 连续拖放、权限变化、组件卸载和网络失败不会产生重复监听或错误状态。
参考:MDN HTML Drag and Drop API、MDN DataTransfer、MDN Pointer Events、W3C WCAG 2.2 Dragging Movements、W3C WCAG 2.2。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。