拖放 dataTransfer.getData 为空

Posted

技术标签:

【中文标题】拖放 dataTransfer.getData 为空【英文标题】:Drag'n'drop dataTransfer.getData empty 【发布时间】:2015-04-13 18:31:43 【问题描述】:

我试图让拖放工作,但我似乎完全错过了 getData/setData 的工作原理。

我正在使用此代码 (http://jsfiddle.net/ASKte/218/)

var el = angular.element(document.getElementById('drag'));
el.attr("draggable", "true");
el.bind("dragstart", function(e) 
    e.dataTransfer.setData('text', 'Where have you gone?!?!')         
);

var target = angular.element(document.getElementById('drop'));
target.bind("dragover", function(e) 
    if (e.preventDefault) 
        e.preventDefault(); // Necessary. Allows us to drop.
    
    return false;
);

target.bind("dragenter", function(e) 
    console.debug(e.dataTransfer.types);
    console.debug(e.dataTransfer.getData('text'));
);

我在这里使用 AngularJS,因为这是一段大得多的代码的 sn-p。

由于某种原因,在底部正方形上拖动顶部正方形时,getData('text') 的值始终为空,但我不知道为什么...

有什么想法吗?

提前致谢。

【问题讨论】:

【参考方案1】:

数据仅在拖放时可用,这是一项安全功能,因为当您碰巧在网页上拖动某些内容时,网站可能会抓取数据。

var el = angular.element(document.getElementById('drag'));
el.attr("draggable", "true");
el.bind("dragstart", function(e) 
    e.dataTransfer.setData('text', 'Where have you gone?!?!')         
);

var target = angular.element(document.getElementById('drop'));
target.bind("dragover", function(e) 
    if (e.preventDefault) 
        e.preventDefault(); // Necessary. Allows us to drop.
    
    return false;
);

target.bind("drop", function(e) 
    console.debug(e.dataTransfer.types);
    console.debug(e.dataTransfer.getData('text'));
);  
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div id="drag" style="width: 100px; height: 100px; background-color: blue;"></div>

<div id="drop" style="width: 100px; height: 100px; background-color: green;"></div>

【讨论】:

啊,我明白了,那太糟糕了。我想根据拖动的内容进行一些动态样式更改。我想我必须想出其他解决方案。 @Robba 你找到解决方案了吗? @Z.Khullah 您可以在拖动期间检查 dataTransfer.types,这将是您作为第一个参数传递给 setData 的字符串数组。因此,您可以例如调用 setData('text', 'my drop data') 和 setData('dropzone1', 'dummy'),然后在 dragover 上检查类型数组以查看它是否包含 dropzone1 或 dropzone2,然后您将知道要设置哪个 dropEffect。 @BrianS 的建议是正确的答案,超级容易实现!请注意 .types 会自动小写,请注意将类型与您的小写 id 进行比较(或确保您的 id 为小写) 这是一个令人讨厌的限制。我了解安全风险,但这应该是可选的附加安全措施,例如限制谁可以看到正在拖动的内容(例如,只有启动拖动的相同 URL/视口)。用例:我需要知道正在拖动哪个特定项目(不仅仅是什么类型的项目),以决定是否可以将其拖放到另一个项目上,以便在用户悬停时提供反馈。【参考方案2】:

如果您真的需要访问其他放置事件中的数据,请使用dataTransfer.types。使用JSON.parseJSON.stringify 和编码/解码大写字符来绕过dataTransfer.types 变成小写。

设置数据:

event.dataTransfer.setData(encodeUpperCase(JSON.stringify(value)), '');

获取数据:

const data = JSON.parse(decodeUpperCase(event.dataTransfer.types[0]))

编码/解码是这样的:

  const UPPERCASE_PREFIX = '^';
  const UPPERCASE_SUFFIX = '^';

  function encodeUpperCase(str: string): string 
    return str.replace(/([A-Z]+)/g, `$UPPERCASE_PREFIX$1$UPPERCASE_SUFFIX`);
  

  function decodeUpperCase(str: string): string 
    const escapeRegExp = (escape: string) => ['', ...escape.split('')].join('\\');

    return str.replace(
      new RegExp(`$escapeRegExp(UPPERCASE_PREFIX)(.*?)$escapeRegExp(UPPERCASE_SUFFIX)`, 'g'),
      (_, p1: string) => p1.toUpperCase()
    );
  

它有效,但你可能会在此过程中召唤克苏鲁。

【讨论】:

以上是关于拖放 dataTransfer.getData 为空的主要内容,如果未能解决你的问题,请参考以下文章

删除事件 dataTransfer.getData() 在 Firefox 上返回 ""

如何在事件 Dragover 或 Dragenter 中从 DataTransfer.getData 获取数据

vue+html5+原生dom+原生JavaScript实现跨区域拖放

$() 函数未按预期工作

html5怎么实现元素随意拖到,是改变位置,不是把元素拖动到另一个元素里面

理论 | HTML5 进阶系列:拖放 API 实现拖放排序