考虑一下这个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);
};
据我所知,这应该可以正常工作,如果你在拖动项目的同时查看控制台,你会看到写出的id,这意味着它正好找到了元素并抓住了它的id属性。问题是,它是不是设置数据还是没有获取数据?
我很欣赏这些建议,因为经过一周的努力,经过三次尝试和200多个版本,我开始放松心情。我所知道的是它曾经在60左右的版本中工作,而且具体的代码根本没有改变......
实际上,6X和124之间的主要区别之一是我将事件绑定从live()
更改为on()
。我不认为这是问题所在,但是在谈到DnD时,我已经看到Chrome出现了几次失败。
这已经被揭穿了。事件绑定方法对此问题没有影响。
UPDATE
我创建了一个新的JSFiddle,它绝对剥离了所有东西,只留下了事件绑定和处理程序。我用jQuery 1.7.2和1.8用on()
和live()
测试了它。问题持续存在,因此我删除了一个级别并删除了所有框架并使用了纯JavaScript。这个问题仍然存在,所以基于我的测试,我的代码不是失败的。相反,Chrome,Safari和Opera似乎都在实施setData()
或getData()
规格,或者由于某种原因而失败。如果我错了,请纠正我。
无论如何,如果你看一下新的JSFiddle,你应该能够复制这个问题,只需在拖动指定接受drop的元素时查看控制台。我已经开始用Chromium开了一张票。最后我可能仍然做错了什么,但我现在根本不知道怎么做DnD。新的JSFiddle就像它可以得到的那样......
好吧,经过多一点挖掘后,我发现问题实际上不是Chrome,Safari和Opera。放弃它的原因是Firefox支持它,我只是不能说其他浏览器都失败了,因为这是我通常接受的IE。
问题的真正原因是DnD specification itself。根据drag
,dragenter
,dragleave
,dragover
和dragend
事件的规范,拖动数据存储模式是保护模式。您问的保护模式是什么?它是:
对于所有其他活动。可以枚举拖动数据存储表示拖动数据的项目列表中的格式和种类,但数据本身不可用,并且不能添加新数据。
这意味着,“你无法访问你设置的数据,甚至不能只读模式!去f @&#self。”。真?谁想出这个天才?
现在,为了解决这个限制,你几乎没有选择,我只想概括两个我想出来的。您的第一个是使用邪恶的全局变量并污染全局命名空间。您的第二选择是使用HTML5 localStorage API来执行与DnD API应该提供的完全相同的功能!
如果你沿着这条路走下去,你现在正在实现两个HTML5 API,不是因为你想要,而是因为你必须这样做。现在我开始欣赏HTML5 DnD API的PPK's rant about the disaster。
最重要的是,需要更改规范以允许访问存储的数据,即使它仅处于只读模式。在我的情况下,with this JSFiddle,我实际上使用dragenter
作为一种方法来展望掉落区域,并验证我应该允许下降发生。
在这种情况下,Mozilla显然选择不完全符合规范,这就是为什么我的JSFiddle工作得很好。碰巧这是我完全支持不支持完整规范的一次。
“受保护”位有一个原因......拖放可以跨越完全不同的窗口,他们不希望有人能够实现一个“监听器”DIV,它会窃听所有内容。拖过它(也许可以通过AJAX将这些内容发送给Elbonia的某个间谍服务器)。只有DROP区域(更明显受用户控制)才能得到完整的独家新闻。
很烦人,但我明白为什么它可能被认为是必要的。
var dragStartHandler = function (e) {
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.setData("text/plain", this.id);
};
问题在于“text / plain”。 setData的MSDN文档中的标准规范只是“文本”(没有/ plain)。在我尝试的任何版本中,Chrome都接受/ plain,但IE不接受。
几个星期以来,我一直在努力解决同样的问题,试图弄清楚为什么我的“掉线”事件在他们在CHrome做的时候没有在IE中正常触发。这是因为dataTransfer数据没有正确加载。
我知道你已经回答了这个,但这是一个有用的线程 - 我只是想在这里添加一个附录 - 如果你自己设置数据,你总是可以将数据添加到字段本身(丑陋我知道),但它可以防止重新创建功能:
例如,如果设置自己的自定义数据:
dataTransfer.setData('mycustom/whatever', 'data');
将数据附加为新数据条目,并迭代:
dataTransfer.setData('mycustom/whatever/data/{a json encoded string even}');
查询:
// 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
}
}
}
仅在镀铬中测试过
值得注意的是,如果您使用超时离开执行链,则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);
}
以下代码我得到了同样的错误:
event.originalEvent.dataTransfer.setData(“text / plain”,event.target.getAttribute('id'));
我将代码更改为:
event.originalEvent.dataTransfer.effectAllowed =“move”; event.originalEvent.dataTransfer.setData(“text”,event.target.getAttribute('id'));
它对我有用。
我遇到过这篇文章,因为我对Chrome的dataTransfer.setData()
和dataTransfer.getData()
功能有类似的体验。
我的代码看起来像这样:
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;
}
代码在Internet Explorer中运行得非常好,但是当它在Chrome中测试时,我无法使用newDrop函数中的dataTransfer
函数在我的dataTransfer.getData()
对象中设置值(在拖动函数中设置)。我也无法从语句ev.target.id
中获取id值。
在网上挖掘了一些之后,我发现我假设使用事件参数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;
}
通过这个改变,我能够使用chrome中的dataTransfer.setData()
和dataTransfer.getData()
函数以及Internet Explorer。我没有在其他任何地方测试过,我不确定为什么会这样。希望这会有所帮助,希望有人可以给出解释。
我正在使用Firefox进行网站测试。
在我的笔记本电脑上的WAMP中,OP的代码工作正常。但是,当我将网站移至HOSTMONSTER时,它在那里无效。
我跟着Joshua Espana的回答,它解决了我的问题。
失败:
ev.dataTransfer.setData("text/plain", ev.target.id);
工作:
ev.dataTransfer.setData("text", ev.currentTarget.id);
谢谢,约书亚!