拖拽目标区域必须设置ondragover并调用preventdefault(),否则ondrop不触发;源元素需设draggable="true",目标区需有min-height;移动端ios safari不支持原生拖拽,需用touch事件模拟。

拖拽目标区域必须设置 ondragover 阻止默认行为
浏览器默认禁止在任意元素上放置拖拽项,所以即使你写了 ondrop,只要没处理 ondragover,拖拽图标就会变成“禁止”符号(圆圈加斜杠),根本放不进去。
关键操作是:在目标容器上监听 ondragover,并在事件处理器中调用 event.preventDefault()。仅此一步,就能让该区域变成合法的 drop zone。
-
ondragover必须存在且调用preventDefault(),否则ondrop永远不会触发 - 不要只靠 CSS 设置
draggable="true"就以为能拖——源元素要设draggable="true",目标区域要主动“接住” - 如果目标区域是空的
<div></div>,记得给它设个最小高度(如min-height: 60px),否则视觉上不可见、实际也无法悬停触发ondragover
ondrop 里怎么拿到被拖进来的元素
HTML5 拖拽 API 不直接传递被拖元素节点,而是通过 dataTransfer 对象传数据。如果你只是想把源元素“移过去”,最可靠的方式不是读取 dataTransfer,而是用 event.target 找到目标区,再把源元素 appendChild 过来——前提是源元素支持 DOM 移动(即不是只读副本)。
常见做法分两类:
- 移动源元素本身:
event.dataTransfer.getData('text/plain')一般为空;更稳的是在ondragstart中用dataTransfer.setData('text/html', '')存个标记,然后在ondrop中通过event.dataTransfer.effectAllowed或自定义dataset辅助识别来源 - 推荐做法:在
ondragstart时给源元素加临时 class(如dragging),在ondrop里用document.querySelector('.dragging')找到它,再appendChild到目标区,最后移除 class - 注意:如果源元素是
contenteditable或表单控件,直接移动可能触发 focus 异常,建议 clone 后插入,原元素留空或隐藏
多个放置区域共存时如何区分目标
当页面有多个可放置容器(比如“待办”“进行中”“已完成”三栏),不能只靠 ondrop 绑定在父容器上——你得知道具体落在哪个子区域内部,尤其是区域有内边距、嵌套子元素时。
解决方法是:把 ondrop 和 ondragover 绑在最精确的容器上(比如每个 <section class="drop-zone"></section>),并利用 event.currentTarget 确保拿到的是当前被拖入的那个区域,而不是它的父级。
- 避免把事件绑在太外层的 wrapper 上,否则
event.target可能是内部文字或图标,导致误判落点 - 可以用
event.currentTarget.dataset.zoneId给每个区域打标,ondrop里直接读这个值做业务分发 - 如果区域之间有间隙,建议用
pointer-events: none在间隙元素上禁用指针,防止dragover中断
移动端 Safari 对 draggable 支持很有限
iOS Safari 默认不响应 draggable="true",也不触发 ondragstart 等事件——这不是 bug,是故意限制。所以纯 HTML5 拖拽在 iPhone/iPad 上基本不可用。
真要支持移动端,得绕开原生 API:
- 用
touchstart/touchmove/touchend模拟拖拽逻辑,配合transform: translate()实时移动元素 - 放置判定改用
Element.getBoundingClientRect()+ 触点坐标比对,而非依赖ondrop - 第三方库如
interact.js或sortablejs(带 touch 插件)更省心,但要注意 bundle 体积和 license
别在开发后期才测 iOS,拖拽逻辑一旦基于原生 API 写死,补移动端成本极高。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











