【问题标题】:Pass object through dataTransfer通过 dataTransfer 传递对象
【发布时间】:2026-01-25 10:15:01
【问题描述】:

我正在尝试找出一种通过 javascript 的 event.dataTransfer 传递原生对象以进行拖放的方法。我正在编写 CMS 的前端编辑器部分,并希望用户能够拖放元素(许多不同类型的元素,从文件到图像到 HTML 的 sn-ps 到几乎任何东西)。这就是为什么我想传递一个真实的对象,所以我可以将数据附加到它以指定为了知道如何呈现它而需要的东西。

一种解决方法是使用 jQuery 的 .data() 将对象附加到页面上的其他内容,然后只需在 setData 中传递选择器字符串...但我并不特别喜欢这种 hack。

这也可以通过 jQuery UI 的可拖放/可拖放来解决(我并不完全反对使用任何库),但由于 dropzone 位于 iframe 中,这实际上是最新 jQuery UI 中记录的错误( 1.10.2)。另外,如果可能的话,我强烈希望在本地进行。此应用中的库已经足够了。

问题来了:http://jsfiddle.net/AHnh8/

var foo = {foo: "foo", bar: "bar"};

$dragme.on("dragstart", function(e) {
    e.originalEvent.dataTransfer.setData("foo", foo);
});

$dropzone.on("dragenter", function(e) { e.preventDefault(); });
$dropzone.on("dragover", function(e) { e.preventDefault(); });
$dropzone.on("drop", function(e) {
    console.log(e.originalEvent.dataTransfer.getData("foo")); // [Object object]
    console.log(typeof e.originalEvent.dataTransfer.getData("foo")); // string
});

现在,在阅读了规范之后,我完全明白为什么会失败。我不明白的是,如何最终实现我想要的。

谢谢

【问题讨论】:

  • 我认为您只需要在发送数据之前对数据进行字符串化,并在接收时解析数据。

标签: jquery html drag-and-drop


【解决方案1】:

在使用setData 之前,您应该将对象传递给JSON.stringify,因为您只能存储字符串。

var j = JSON.stringify(foo);
e.originalEvent.dataTransfer.setData("foo", j);

反之,你必须将字符串重新转换为对象:

var obj = JSON.parse(e.originalEvent.dataTransfer.getData("foo"));
console.log("foo is:", obj);

this工作小提琴

【讨论】:

  • 我发帖后也考虑过这个,虽然我还是觉得应该有办法传递一个对象?
  • 我认为没有办法。但是您可以添加一个全局数组来存储数据,然后将密钥传递给set/getData。也许对于较大的物体来说它更快
  • 我认为这种方式在这种情况下效率很低。编码/解码过程是额外的开销,并且对象将被不必要地复制。临时全局数组似乎是暂时处理此问题的最佳方法。
  • 除非您要删除大量 JSON 对象,否则我看不出这会是多么低效。这样您也可以从其他选项卡中删除内容!
  • 这不仅仅是 json 编码/解码开销。更重要的是你失去了对原始对象的引用,所以你不能轻易改变它。例如,在 Vuejs 中这是一个问题,一切都基于数据(对象、数组),在拖放操作中直接引用它们会很方便。
【解决方案2】:

也许我要提出的建议是错误的(如果是这样,我会很高兴听到为什么)。 为什么不在dragstart监听器中设置一个变量来引用你所需要的,例如:

//global variable
var obj;

//set the global variable to wahtever you wish in the dragstart:
$dragme.on("dragstart", function(e) {
    obj = foo;
    //or even obj = document.getElementById("some element's id");
});

//use this obj in the drop listener.
$dropzone.on("drop", function(e) {
    obj.doWahtEver();
});

【讨论】:

  • bc globals = :( .. 有很多像这样的简单解决方法。我最初发布这个问题是因为我想知道你是否可以通过 dataTransfer 传递一个对象。事实证明你不能.
  • @Kabir,但它比序列化/反序列化更正确,从文档中您应该能够看到数据的 fromat 是developer.mozilla.org/en-US/docs/Web/API/DOMString