HTML5 DnD dataTransfer setData或getData在除Firefox之外的每个浏览器中都不起作用

时间:2012-08-13 01:44:14

标签: javascript jquery html5 drag-and-drop

考虑这个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出现了几次失败。这已经被揭穿了。事件绑定方法对此问题没有影响。

更新

我创建了一个新的JSFiddle,它可以删除所有内容,只留下事件绑定和处理程序。我使用jQuery 1.7.2和1.8对on()live()进行了测试。问题持续存在,因此我删除了一个级别并删除了所有框架并使用了纯JavaScript。问题仍然仍然存在,因此根据我的测试,我的代码不是失败的。相反,Chrome,Safari和Opera似乎都在实施setData()getData()规范,或者由于某种原因而失败。如果我错了,请纠正我。

无论如何,如果您查看新的JSFiddle,您应该能够复制该问题,只需在拖动指定为接受放置的元素时查看控制台即可。我已经开始用Chromium打开一张票。最后我可能仍然做错了什么,但我现在根本不知道怎么做DnD。新的JSFiddle就像它可以得到的那样......

8 个答案:

答案 0 :(得分:68)

好的,经过多一点挖掘后,我发现问题实际上并不在于Chrome,Safari和Opera。放弃它的原因是Firefox支持它,我只是不能说其他浏览器都失败了,因为这是我通常接受的IE。

问题的真正原因是DnD specification itself。根据{{​​1}},dragdragenterdragleavedragover事件的规范,拖动数据存储模式为保护模式。您问的保护模式是什么?它是:

  

适用于所有其他活动。拖动数据存储中的格式和种类   表示拖动数据的项目列表可以枚举,但是   数据本身不可用,无法添加新数据。

这意味着,“您无权访问您设置的数据,即使在只读模式下也无法访问!请自行查看#&#; em。”。真?谁是提出这个的天才?

现在,为了解决这个限制,你几乎没有选择,我只想概括两个我想出来的。您的第一个是使用邪恶的全局变量并污染全局命名空间。您的第二选择是使用HTML5 localStorage API来执行与DnD API应该提供的完全相同的功能!

如果你沿着这条路走下去,你现在正在实施两个HTML5 API,不是因为你想要,而是因为你拥有。现在我开始感谢HTML5 DnD API的PPK's rant about the disaster

最重要的是,需要更改规范以允许访问存储的数据,即使它仅处于只读模式。在我的情况下,with this JSFiddle,我实际上使用dragend作为展望放置区的方法,并验证我是否应该允许丢弃。

在这种情况下,Mozilla显然选择不完全符合规范,这就是为什么我的JSFiddle工作正常。碰巧这是有一次我完全支持不支持完整的规范。

答案 1 :(得分:15)

“受保护”位有一个原因....拖放可以跨越完全不同的窗口,并且他们不希望有人能够实现一个“监听器”DIV,它会窃听内容所有被拖过它的东西(也许可以通过AJAX将这些内容发送给Elbonia的某个间谍服务器)。只有DROP区域(更明显地受用户控制)才能获得完整的独家消息。

很烦人,但我明白为什么它可能被认为是必要的。

答案 2 :(得分:12)

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数据没有正确加载。

答案 3 :(得分:5)

我知道你已经回答了这个问题,但这是一个有用的主题 - 我只是想在这里添加一个附录 - 如果你自己设置数据,你总是可以将数据添加到字段本身(丑陋的我知道),但它可以防止不得不重新创建功能:

例如,如果要设置自己的自定义数据:

  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
        }
    }
}

仅在镀铬中测试

答案 4 :(得分:2)

还值得注意的是,如果您使用超时离开执行链,则dataTransfer对象将不再拥有您的数据。 e.g。

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);
}

答案 5 :(得分:1)

我在下面的代码中遇到了同样的错误:

  

event.originalEvent.dataTransfer.setData( “text / plain的”,   event.target.getAttribute( '编号'));

我将代码更改为:

  

event.originalEvent.dataTransfer.effectAllowed =“move”;           event.originalEvent.dataTransfer.setData(“text”,event.target.getAttribute('id'));

它对我有用。

答案 6 :(得分:1)

之所以遇到此帖子,是因为我在使用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中对其进行测试后,我无法使用dataTransfer函数中的dataTransfer.getData()对象来获取在ev.target.id对象中设置的值(在拖动函数中设置)。 newDrop函数。我也无法从语句currentTarget中获取id值。

在网络上进行了一些探索之后,我发现我应该使用事件参数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; } 属性。更新的代码如下所示:

dataTransfer.setData()

通过此更改,我能够在chrome和Internet Explorer中使用dataTransfer.getData()和{{1}}函数。我没有在其他任何地方进行测试,并且不确定为什么会奏效。希望这会有所帮助,并希望有人能给出解释。

答案 7 :(得分:0)

我正在使用Firefox进行网站测试。

在笔记本电脑上的WAMP中,代码像OP一样起作用。但是,当我将网站移至HOSTMONSTER时,该网站无法正常运行。

我遵循了Joshua Espana的回答,它解决了我的问题。

失败:

ev.dataTransfer.setData("text/plain", ev.target.id);

工作:

 ev.dataTransfer.setData("text", ev.currentTarget.id);

谢谢约书亚!