拖拽时 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 里是空字符串
}
首先,确保在 dragStart 事件中设置了正确的数据格式,这点你已经做了,没问题。但是 Firefox 可能对自定义类型识别不敏感,我们可以稍微变通一下,比如用一个 Firefox 更容易接受的类型,然后再在后台解析成你需要的格式。
你可以试试用 text/plain 来替代 application/json,然后在获取数据后手动解析 JSON。虽然这不是最优解,但至少能绕过 Firefox 的这个坑。
代码示例如下:
pre class="pure-highlightjs line-numbers">
dragStart(e) {
const data = JSON.stringify({ id: 123, type: 'file' });
e.dataTransfer.setData('text/plain', data); // 使用 text/plain 替代 application/json
}
drop(e) {
const data = e.dataTransfer.getData('text/plain');
const parsedData = JSON.parse(data); // 手动解析 JSON 字符串
console.log(parsedData); // 这样应该就能看到正确的对象了
}
这样改之后,应该就能在 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 就都能跑了。