拖放交互¶
学习目标¶
- 理解 HTML Drag and Drop 的事件与数据传递。
- 实现不依赖拖放的键盘、触屏替代操作。
- 安全处理拖入文本、链接和文件。
核心概念¶
元素设置 draggable="true" 后可触发 dragstart,放置目标需要在 dragover 中阻止
默认行为,并在 drop 中读取 DataTransfer。原生拖放在桌面浏览器较常见,但触屏、
键盘和辅助技术支持不一致,因此不能作为完成任务的唯一方式。
安全可运行示例¶
下面既支持拖放,也提供“移动”按钮。状态变化通过文字区域播报:
<ul id="source"><li id="task" draggable="true">整理文档</li></ul>
<h2>已完成</h2>
<ul id="done" aria-label="已完成任务"></ul>
<button id="move" type="button">将“整理文档”移到已完成</button>
<p id="status" role="status"></p>
<script>
const task = document.querySelector('#task');
const done = document.querySelector('#done');
const status = document.querySelector('#status');
function moveTask() {
done.append(task);
task.draggable = false;
status.textContent = '已将整理文档移到已完成。';
}
task.addEventListener('dragstart', event => {
event.dataTransfer.setData('text/plain', task.id);
});
done.addEventListener('dragover', event => event.preventDefault());
done.addEventListener('drop', event => {
event.preventDefault();
if (event.dataTransfer.getData('text/plain') === task.id) moveTask();
});
document.querySelector('#move').addEventListener('click', moveTask);
</script>
真实排序还应提供“上移”“下移”按钮或可操作菜单,并在服务端重新验证对象身份、归属、 目标位置和权限。前端传来的 ID 与顺序都是不可信数据。
文件拖放¶
文件来自 event.dataTransfer.files。客户端应限制可接受类型和大小以改善体验,服务端仍须
检查实际格式、大小、数量、文件名和处理时间,并存放在不可执行位置。不要自动打开或
执行拖入内容;外部 URL 和 HTML 字符串也不能直接插入页面。
兼容与无障碍¶
- 始终提供按钮、文件选择器或表单等键盘/触屏替代。
- 拖动手柄要有可访问名称,操作结果使用文本反馈。
- 不以精细指针、悬停或视觉位置作为唯一线索。
- 在触屏设备和键盘模式下完成完整流程测试。
常见错误¶
- 只监听鼠标事件,认为它等同于拖放和触屏。
- 只显示颜色变化,没有文字说明当前放置目标。
- 信任拖入文件的扩展名、MIME 声明或客户端校验。
- 将
text/html数据直接赋给innerHTML。 - 没有取消默认
dragover,导致drop不触发。