判断拖放内容类型需综合e.dataTransfer.types和e.dataTransfer.files.length:files.length>0且types含'Files'为真实文件(需校验size>0);files.length为0且types含'text/plain'或'text/html'为文本/HTML;含'text/uri-list'为链接;files.length>0但无'Files'类型属异常应拒绝。

怎么判断拖进来的是文本还是文件
关键看 e.dataTransfer.types 和 e.dataTransfer.files.length 的组合结果,不能只依赖其中一个。浏览器对文本、链接、文件的拖放行为底层处理不同,types 是源头声明的“我是什么”,files 是实际附带的“我带了什么”。
常见错误是仅用 e.dataTransfer.files.length > 0 判断是否为文件——它在 Safari 拖入文件夹时也返回 true(但实际是 68 字节伪文件),而在拖入纯文本时又总是 0,导致误判。
-
e.dataTransfer.files.length > 0且e.dataTransfer.types.includes('Files')→ 大概率是真实文件(但仍需校验file.size > 0) -
e.dataTransfer.files.length === 0且e.dataTransfer.types.includes('text/plain')或'text/html'→ 文本或 HTML 片段 -
e.dataTransfer.files.length === 0且e.dataTransfer.types.includes('text/uri-list')→ 拖入的是链接(URL) -
e.dataTransfer.files.length > 0但!e.dataTransfer.types.includes('Files')→ 异常情况(如某些 WebView 伪造数据),应拒绝处理
为什么 e.dataTransfer.getData('text/plain') 有时返回空字符串
因为不是所有拖放源都设置了 text/plain 类型的数据。浏览器只对选中文本、地址栏 URL、部分编辑器内容自动填充该类型;而文件拖放默认不设 text/plain,即使你调用 getData('text/plain') 也会返回空字符串或 null。
更稳妥的做法是先查 types 列表,再按需取值:
- 有
'text/plain'→e.dataTransfer.getData('text/plain') - 有
'text/html'→e.dataTransfer.getData('text/html') - 有
'text/uri-list'→e.dataTransfer.getData('text/uri-list'),然后取首行(URL 通常在第一行) - 以上都没有 → 不是文本类拖放,别硬读
如何安全过滤 Safari 文件夹拖入这个坑
Safari 允许用户直接拖拽整个文件夹到网页,但返回的 File 对象是伪装的:大小固定为 68 字节,file.name 没有扩展名(如只是 "MyFolder"),file.type 为空字符串。如果直接上传,后端收到的是无效二进制垃圾。
必须在拿到 files 后立刻逐个检查:
- 用
Array.from(e.dataTransfer.files)转成真数组(FileList不能直接filter) - 对每个
file,同时判断:file.size === 68 && !/\.\w+$/.test(file.name) - 满足上述条件的,视为 Safari 文件夹,直接跳过或报错提示,不要尝试读取或上传
- 额外建议:检查
file.webkitRelativePath—— 文件夹里的子文件会带路径,根文件夹则为空,可辅助识别
移动端和 WebView 下的兼容性现实
Android WebView 和 iOS Safari(尤其是 16.4+ 之前)对 dragover/drop 支持极差,很多情况下 e.dataTransfer.files 始终为空,types 也不可靠。这不是代码写错了,是平台限制。
不要试图在这些环境里强行统一逻辑,而是做降级:
- 检测
typeof window.ondragover === 'undefined'或监听dragover是否触发 - 若不可靠,隐藏拖拽区,只保留
并用click()触发(iOS Safari 必须这样) - 别依赖
e.dataTransfer.items—— 它在移动端基本不可用,files才是唯一相对稳定的入口 - 测试时务必用真机,模拟器的拖放行为和真实用户操作差异极大
最易被忽略的一点:dragenter 和 dragover 的触发频率极高(每 30–50ms 一次),任何同步耗时操作(比如遍历 files、调 getData)都会卡 UI。类型判断逻辑必须只放在 drop 里做,dragover 里只做 preventDefault() 和 class 切换。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











