拖拽时 DataTransfer 的 setData 为什么在 Firefox 里取不到值?
我在做一个拖拽上传的功能,用 setData 存了个自定义类型的数据,Chrome 下一切正常,但在 Firefox 里 getData 拿到的是空字符串。是不是 Firefox 对自定义 MIME 类型支持有问题?
我试过换成 text/plain 就可以,但我想传结构化数据,所以用了 application/json。代码大概是这样:
dragStart(e) {
const data = JSON.stringify({ id: 123, type: 'file' });
e.dataTransfer.setData('application/json', data);
}
drop(e) {
const data = e.dataTransfer.getData('application/json');
console.log(data); // Firefox 里是空字符串
}
原理是这样:Firefox 默认只支持几种特定的类型,比如 text/plain、text/uri-list 和 text/html。如果你尝试设置一个不在白名单里的类型(比如你的 application/json),Firefox 会静默失败,不会报错,但数据根本没存进去,所以 drop 的时候自然拿不到值。Chrome 这方面比较宽松,允许开发者自定义任意类型。
解决方案其实很简单,不用纠结 application/json,直接用 text/plain 存你的 JSON 字符串就行。反正数据都在字符串里,只要存进去、取出来的时候格式是对的,业务逻辑完全不受影响。
看一下修改后的代码:
还有个小细节要注意,如果你要兼容拖拽到外部(比如拖拽文本到编辑器里),可能还需要设置 text/uri-list,但如果你只是在页面内部做逻辑交互,text/plain 就足够应付所有浏览器了。
另外,Firefox 还有个历史遗留问题,就是在 drop 事件里读取数据时,有些旧版本要求必须在 dragover 事件里调用 preventDefault(),否则 drop 事件根本不会触发。虽然你现在的报错是取不到值,但也顺便检查一下 dragover 处理没:
这一套下来,Chrome、Firefox、Safari 就都能跑了。