draggable="true"仅开启可拖状态,不自动触发事件;必须监听dragstart并调用setData("text/plain",""),且drop区需在dragover中preventDefault()。
draggable="true"只是拖拽流程的起点,不是开关——设了它,拖拽事件仍不会自动触发,必须配齐事件监听和 dataTransfer 操作。
浏览器只对 <img>、带 href 的 <a>、选中的文本这三类元素启用原生拖拽逻辑;其他元素(比如 <div>)即使写了 draggable="true",也只会“视觉上可拖”,实际不触发 dragstart 事件。
dragstart 事件,并在其中调用 event.dataTransfer.setData()(哪怕只塞一个空字符串,如 setData("text/plain", ""))user-select: none 或 pointer-events: none,会直接拦截鼠标按下阶段,导致拖拽根本无法开始draggable 属性必须写在被拖元素自身上,不能只写在父容器里type 字符串不是随便起的别名,而是有浏览器隐式校验的 MIME 类型标识。填错会导致 Firefox 完全拒绝接收、Chrome 返回空字符串。
"text/plain" 和 "text/html";结构化数据先 JSON.stringify() 再存进 "text/plain"
"app/id"、"json"),除非你确定所有拖放逻辑都在同页面内,且完全控制两端事件处理setData("Text", "value") 中的 "Text" 是过时写法,部分浏览器已不识别,统一用小写 "text/plain"
90% 的原因是 dragover 事件里没调用 preventDefault()。这不是“优化建议”,而是浏览器强制链路:没有它,drop 事件压根不会派发。
立即学习“前端免费学习笔记(深入)”;
dragover,并在回调中同步执行 event.preventDefault()
dragover 可能高频冒泡,建议绑定在父级并用 event.stopPropagation() 控制范围dropzone 属性早已废弃,现代浏览器无视它,别再指望靠这个“自动启用”真正卡住的地方往往不在逻辑设计,而在 dragstart 是否真被触发、dragover 是否真被阻止、setData 的 type 是否被浏览器认可——这三个点一漏,整个拖拽链就断在起点,连调试器都看不到后续事件。