拖拽时 DataTransfer 的 setData 为什么在 Firefox 里取不到值?

爱学习的艺嘉 阅读 14

我在做一个拖拽上传的功能,用 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 里是空字符串
}
我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
设计师婉琳
这事儿我之前也踩过坑,Firefox 对 DataTransfer 的安全策略确实比 Chrome 严格得多。并不是 Firefox 不支持自定义 MIME 类型那么简单,而是它出于安全考虑,把支持的类型做了白名单限制。

原理是这样:Firefox 默认只支持几种特定的类型,比如 text/plain、text/uri-list 和 text/html。如果你尝试设置一个不在白名单里的类型(比如你的 application/json),Firefox 会静默失败,不会报错,但数据根本没存进去,所以 drop 的时候自然拿不到值。Chrome 这方面比较宽松,允许开发者自定义任意类型。

解决方案其实很简单,不用纠结 application/json,直接用 text/plain 存你的 JSON 字符串就行。反正数据都在字符串里,只要存进去、取出来的时候格式是对的,业务逻辑完全不受影响。

看一下修改后的代码:

// 拖拽开始时
dragStart(e) {
const data = JSON.stringify({ id: 123, type: 'file' });
// 这里改成 'text/plain',兼容性最好
// 只要内容是 JSON 字符串,取出来解析一下就行
e.dataTransfer.setData('text/plain', data);
}

// 放下时
drop(e) {
// 对应取 'text/plain'
const rawData = e.dataTransfer.getData('text/plain');

// 记得做个判空保护,防止有些浏览器或意外情况拿到空值
if (rawData) {
try {
const data = JSON.parse(rawData);
console.log(data); // { id: 123, type: 'file' }
} catch (err) {
console.error('数据解析失败', err);
}
}
}


还有个小细节要注意,如果你要兼容拖拽到外部(比如拖拽文本到编辑器里),可能还需要设置 text/uri-list,但如果你只是在页面内部做逻辑交互,text/plain 就足够应付所有浏览器了。

另外,Firefox 还有个历史遗留问题,就是在 drop 事件里读取数据时,有些旧版本要求必须在 dragover 事件里调用 preventDefault(),否则 drop 事件根本不会触发。虽然你现在的报错是取不到值,但也顺便检查一下 dragover 处理没:

dragOver(e) {
// 必须阻止默认行为,否则 drop 事件不会触发
e.preventDefault();
}


这一套下来,Chrome、Firefox、Safari 就都能跑了。
点赞
2026-02-28 23:01