拖放 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.parse
、JSON.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实现跨区域拖放