Javascript HTML5 DnD dataTransfer setData 或 getData 不适用于除 Firefox 之外的所有浏览器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11927309/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HTML5 DnD dataTransfer setData or getData not working in every browser except Firefox
提问by Gup3rSuR4c
Consider this JSFiddle. It works fine in Firefox (14.0.1), but fails in Chrome (21.0.1180.75), Safari (?) and Opera(12.01?) on both Windows (7) and OS X (10.8). As far as I can tell the issue is with either the setData()
or getData()
methods on the dataTransfer
object. Here's the relevant code from the JSFiddle.
考虑这个JSFiddle。它在 Firefox (14.0.1) 中运行良好,但在 Windows (7) 和 OS X (10.8) 上的 Chrome (21.0.1180.75)、Safari (?) 和 Opera(12.01?) 中失败。据我所知,问题出在对象上的setData()
或getData()
方法上dataTransfer
。这是来自 JSFiddle 的相关代码。
var dragStartHandler = function (e) {
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.setData("text/plain", this.id);
};
var dragEnterHandler = function (e) {
// dataTransferValue is a global variable declared higher up.
// No, I don't want to hear about why global variables are evil,
// that's not my issue.
dataTransferValue = e.originalEvent.dataTransfer.getData("text/plain");
console.log(dataTransferValue);
};
As far as I can tell this should work perfectly fine and if you look at the console while dragging an item you will see the id written out, which means that it's finding the element just fine and grabbing it's id attribute. The question is, is it just not setting the data or not getting the data?
据我所知,这应该可以正常工作,如果您在拖动项目时查看控制台,您将看到写出的 id,这意味着它正在很好地找到元素并获取它的 id 属性。问题是,是不设置数据还是不获取数据?
I'd appreciate suggestions because after a week of working on this with three attempts and some 200+ versions, I'm starting to loose my mind. All I know is it used to work back in version 60 or so and that specific code hasn't changed at all...
我很感激建议,因为经过一周的三个尝试和大约 200 多个版本的工作后,我开始失去理智。我所知道的是它曾经在 60 版左右的版本中工作过,并且特定的代码根本没有改变......
Actually, one of the major differences between 6X and 124 is that I changed the event binding from This has been debunked. The event binding method has no effect on the issue.live()
to on()
. I don't think that's the issue, but I've come to see a couple failures from Chrome when it comes to DnD while working on this.
实际上,6X 和 124 之间的主要区别之一是我将事件绑定从 更改这已被揭穿。事件绑定方法对该问题没有影响。live()
为on()
。我不认为那是问题所在,但是在处理此问题时,我已经看到 Chrome 在 DnD 方面出现了一些失败。
UPDATE
更新
I've created a new JSFiddlethat strips out absolutely everything and just leaves the event binding and handlers. I tested it with jQuery 1.7.2 and 1.8 with both on()
and live()
. The issue persisted so I dropped down a level and removed all frameworks and used pure JavaScript. The issue stillpersisted, so based on my testing it's not my code that's failing. Instead it appears that Chrome, Safari and Opera are all implementing either setData()
or getData()
off spec or just failing for some reason or another. Please correct me if I'm wrong.
我创建了一个新的JSFiddle,它完全去除了所有东西,只留下事件绑定和处理程序。我用jQuery 1.7.2和1.8既测试了它on()
和live()
。问题仍然存在,所以我降低了一个级别并删除了所有框架并使用了纯 JavaScript。问题仍然存在,因此根据我的测试,失败的不是我的代码。相反,Chrome、Safari 和 Opera 似乎都在实现setData()
或getData()
不符合规范,或者只是出于某种原因而失败。如果我错了,请纠正我。
Anyway, if you take a look at the new JSFiddle you should be able to replicate the issue, just look at the console when you're dragging over an element designated to accept a drop. I've gone ahead and opened a ticket with Chromium. In the end I may still be doing something wrong, but I simply don't know how else to do DnD at this point. The new JSFiddle is as stripped down as it can get...
无论如何,如果您查看新的 JSFiddle,您应该能够复制该问题,只需在拖动指定接受放置的元素时查看控制台即可。我已经继续使用Chromium开了一张票。最后我可能仍然做错了什么,但我现在根本不知道如何做 DnD。新的 JSFiddle 尽可能精简......
回答by Gup3rSuR4c
Ok, so after a bit more digging around, I found that the problem actually isn't with Chrome, Safari, and Opera. What gave it away was that Firefox was supporting it and I just couldn't say the other browsers are failing, since that's something I'd normally accept for IE.
好的,经过更多的挖掘,我发现问题实际上不在于 Chrome、Safari 和 Opera。放弃它的是 Firefox 支持它,我不能说其他浏览器都失败了,因为这是我通常会接受的 IE 浏览器。
The real cause of the issue is the DnD specification itself. According to the spec for the drag
, dragenter
, dragleave
, dragover
and dragend
events the drag data store mode is protected mode. What is protected modeyou ask? It is:
问题的真正原因是DnD 规范本身。根据规范的drag
,dragenter
,dragleave
,dragover
和dragend
事件拖拽数据存储模式保护模式。你问什么是保护模式?这是:
For all other events. The formats and kinds in the drag data store list of items representing dragged data can be enumerated, but the data itself is unavailable and no new data can be added.
对于所有其他事件。拖拽数据存储列表中表示拖拽数据的项的格式和种类可以枚举,但是数据本身是不可用的,也不能添加新的数据。
That translates to, "you have no access to the data that you set, not even in read only mode! Go f@&# yourself.". Really? Who'se the genius that came up with this?
这意味着,“您无权访问您设置的数据,即使在只读模式下也无法访问!自己去 f@&#。” . 真的吗?提出这个问题的天才是谁?
Now, to get around that limitation you have few choices, and I'm only going to outline two that I've come up with. Your first one is to use an evil global variable and pollute the global namespace. Your second choice is to use the HTML5 localStorage API to perform the EXACT same functionality that the DnD API should have provided to begin with!
现在,为了解决这个限制,你几乎没有选择,我将只概述我想出的两个。你的第一个是使用一个邪恶的全局变量并污染全局命名空间。您的第二个选择是使用 HTML5 localStorage API 来执行 DnD API 应该提供的完全相同的功能!
If you go down this route, which I have, you're now implementing two HTML5 APIs not because you wantto, but because you haveto. Now I'm starting to appreciate PPK's rant about the disasterthat the HTML5 DnD API is.
如果你沿着我的这条路线走下去,你现在正在实现两个 HTML5 API,不是因为你想要,而是因为你必须这样做。现在我开始欣赏PPK 关于HTML5 DnD API 是灾难的咆哮。
The bottom line is this, the spec needs to be changed to allow for access to the stored data even if it's only in read only mode. In my case, with this JSFiddle, I'm actually using the dragenter
as a way to look ahead at the drop zone and verify that I should allow a drop to occur or not.
最重要的是,需要更改规范以允许访问存储的数据,即使它仅处于只读模式。就我而言,使用这个 JSFiddle,我实际上是在使用dragenter
来查看放置区并验证我是否应该允许放置发生。
In this case Mozilla apparently opted out of full compliance with the spec which is why my JSFiddle was working just fine in it. It just so happens that this is the one time I fully support not supporting the full specification.
在这种情况下,Mozilla 显然选择不完全遵守规范,这就是为什么我的 JSFiddle 在其中工作得很好。碰巧这是我完全支持不支持完整规范的一次。
回答by Jens Fiederer
There is a reason for the "protected" bit....drag/drop can span completely different windows, and they didn't want somebody to be able to implement a "listener" DIV that would eavesdrop on the content of everything that was dragged over it (and maybe send those contents by AJAX to some spy server in Elbonia). Only the DROP area (which is more clearly under the user's control) gets the full scoop.
“受保护”位是有原因的....拖放可以跨越完全不同的窗口,他们不希望有人能够实现一个“侦听器”DIV 来窃听所有内容的内容拖过它(并且可能通过 AJAX 将这些内容发送到 Elbonia 的某个间谍服务器)。只有 DROP 区域(更清楚地在用户的控制之下)获得完整的独家新闻。
Annoying, but I can see why it might be considered necessary.
烦人,但我明白为什么它可能被认为是必要的。
回答by Roland
var dragStartHandler = function (e) {
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.setData("text/plain", this.id);
};
The problem is with the "text/plain". The standard specification in MSDN documentation for setData is just "text" (without the /plain). Chrome accepts the /plain, but IE does not, in any version I tried.
问题在于“文本/纯文本”。MSDN 文档中 setData 的标准规范只是“文本”(没有 /plain)。在我尝试过的任何版本中,Chrome 都接受 /plain,但 IE 不接受。
I struggled with the same problem for several weeks, trying to figure out why my "drop" events weren't firing properly in IE while they did in CHrome. It was because the dataTransfer data hadn't been properly loaded.
几个星期以来,我一直在为同样的问题苦苦挣扎,试图弄清楚为什么我的“drop”事件在 IE 中没有正确触发,而在 CHrome 中却没有。这是因为 dataTransfer 数据没有正确加载。
回答by ansiart
I know you already answered this, but this is a useful thread -- I just wanted to add an addendum here -- if you're setting the data yourself, you can always add the data into the field itself (ugly I know), but it prevents having to re-create functionality:
我知道你已经回答了这个问题,但这是一个有用的线程——我只是想在这里添加一个附录——如果你自己设置数据,你总是可以将数据添加到字段本身中(我知道很丑),但它可以防止必须重新创建功能:
For instance, if setting your own custom data:
例如,如果设置您自己的自定义数据:
dataTransfer.setData('mycustom/whatever', 'data');
append the data as a new data entry, and iterate:
将数据附加为新数据条目,并迭代:
dataTransfer.setData('mycustom/whatever/data/{a json encoded string even}');
querying:
查询:
// naive webkit only look at the datatransfer.types
if (dataTransfer.types.indexOf('mycustom/whatever') >= 0) {
var dataTest = 'mycustom/whatever/data/';
// loop through types and create a map
for (var i in types) {
if (types[i].substr(0, dataTest.length) == dataTest) {
// shows:
// {a json encoded string even}
console.log('data:', types[i].substr(dataTest.length));
return; // your custom handler
}
}
}
tested in chrome only
仅在 chrome 中测试
回答by Nate Bosscher
Something also worth noting is that if you leave the execution chain using a timeout, the dataTransfer object won't have your data anymore. e.g.
还有一点值得注意的是,如果您使用超时离开执行链,则 dataTransfer 对象将不再拥有您的数据。例如
function dropEventHandler(event){
var dt = event.dataTransfer.getData("text/plain"); // works
var myEvent = event;
setTimeout(function(){
var dt = myEvent.dataTranfer.getData("text/plain"); // null
}, 1);
}
回答by RoshanZ
I was getting same error for below code:
对于以下代码,我遇到了相同的错误:
event.originalEvent.dataTransfer.setData("text/plain", event.target.getAttribute('id'));
event.originalEvent.dataTransfer.setData("text/plain", event.target.getAttribute('id'));
I Changed code to:
我将代码更改为:
event.originalEvent.dataTransfer.effectAllowed = "move"; event.originalEvent.dataTransfer.setData("text", event.target.getAttribute('id'));
event.originalEvent.dataTransfer.effectAllowed = "移动"; event.originalEvent.dataTransfer.setData("text", event.target.getAttribute('id'));
And it worked for me.
它对我有用。
回答by Joshua Espana
I came across this post because I was having a similar experience with Chrome's dataTransfer.setData()
and dataTransfer.getData()
functions.
我看到这篇文章是因为我对 Chrome 的功能dataTransfer.setData()
和dataTransfer.getData()
功能有类似的体验。
I had code that looked something like this:
我的代码看起来像这样:
HTML:
<div ondragstart="drag(event)" ondrop="newDrop(event)"></div>
JAVASCRIPT:
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function newDrop(ev){
var itemDragged = ev.dataTransfer.getData("text");
var toDropTo = ev.target.id;
}
The code worked perfectly fine in Internet Explorer but when it was tested in Chrome, I was unable to get values set in my dataTransfer
object (set in drag function) using the dataTransfer.getData()
function in the newDrop function. I was also unable to get the id value from the statement ev.target.id
.
该代码在 Internet Explorer 中运行良好,但在 Chrome 中进行测试时,我无法dataTransfer
使用dataTransfer.getData()
newDrop 函数中的函数在我的对象中设置值(在拖动函数中设置)。我也无法从语句中获取 id 值ev.target.id
。
After some digging around on the web, I discovered that I was suppose to use the event parameters currentTarget
property rather than the events target
property. Updated code looked something like this:
在网络上进行了一些挖掘之后,我发现我应该使用事件参数currentTarget
属性而不是事件target
属性。更新后的代码如下所示:
JAVASCRIPT:
function drag(ev) {
ev.dataTransfer.setData("text", ev.currentTarget.id);
}
function newDrop(ev){
var itemDragged = ev.dataTransfer.getData("text");
var toDropTo = ev.currentTarget.id;
}
With this change I was able to use the dataTransfer.setData()
and dataTransfer.getData()
functions in chrome as well as internet explorer. I have not tested anywhere else and I am not sure why this worked. Hope this helps and hopefully someone can give an explanation.
通过此更改,我能够在 chrome 和 Internet Explorer 中使用dataTransfer.setData()
和dataTransfer.getData()
功能。我没有在其他任何地方进行过测试,我不确定为什么会这样。希望这会有所帮助,并希望有人可以给出解释。
回答by james
I was working on a website testing with Firefox.
我正在使用 Firefox 进行网站测试。
In WAMP on my laptop, code like the OP's worked. However, when I moved the website to HOSTMONSTER, it didn't work there.
在我的笔记本电脑上的 WAMP 中,像 OP 一样的代码工作正常。但是,当我将网站移至 HOSTMONSTER 时,它在那里不起作用。
I followed Joshua Espana's answer, and it resolved my problem.
我遵循了 Joshua Espana 的回答,它解决了我的问题。
failed:
失败的:
ev.dataTransfer.setData("text/plain", ev.target.id);
worked:
工作:
ev.dataTransfer.setData("text", ev.currentTarget.id);
Thank, Joshua!
谢谢,约书亚!