Tre*_*ham 64 javascript html5 draggable
我正在尝试使用HTML5可拖动的API(虽然我意识到它有它的问题).到目前为止,我遇到的唯一一个显示是我无法找到一种方法来确定当一个dragover或dragenter事件触发时被拖动的内容:
el.addEventListener('dragenter', function(e) {
// what is the draggable element?
});
Run Code Online (Sandbox Code Playgroud)
我意识到我可以认为它是发射dragstart事件的最后一个元素,但是......多点触控.我也试着使用e.dataTransfer.setData从dragstart附加一个唯一的标识符,但显然这些数据是不可访问从dragover/ dragenter:
只有在丢弃事件期间发生丢弃时,才能使用此数据.
那么,有什么想法吗?
更新:在撰写本文时,HTML5拖放似乎没有在任何主流移动浏览器中实现,因此在实践中提出了关于多点触控的观点.但是,我想要一个可以保证在规范的任何实现中都能使用的解决方案,这似乎不会阻止同时拖动多个元素.
我在下面发布了一个有效的解决方案,但这是一个丑陋的黑客攻击.我仍然希望有更好的答案.
bla*_*man 57
我想在这里添加一个非常明确的答案,这样对于那些在这里徘徊的人来说显而易见.在其他答案中已多次说过,但在这里,我可以清楚地说出来:
dragover 没有权利在拖动事件中查看数据.此信息仅在DRAG_START和DRAG_END(丢弃)期间可用.
问题是它根本不明显并且令人抓狂,直到你碰巧在这里的规格或地点上读得太深.
解决方法:
作为一种可能的解决方法,我已经为DataTransfer对象添加了特殊键并对其进行了测试.例如,为了提高效率,我想在我的拖动开始时查找一些"放下目标"规则,而不是每次发生"拖拽"时.为此,我添加了将每个规则标识到dataTransfer对象上的密钥,并使用"contains"对其进行了测试.
ev.originalEvent.dataTransfer.types.includes("allow_drop_in_non_folders")
Run Code Online (Sandbox Code Playgroud)
这样的事情.需要明确的是,"包含"并不是一个神奇的子弹,可以成为一个性能问题本身.注意了解您的使用情况和方案.
Tre*_*ham 21
简短的回答我的问题真可谓是:否.WHATWG规范不提供在被拖动的元素(称为规范"源节点")的引用dragenter,dragover或dragleave事件.
为什么不?两个原因:
首先,正如Jeffery在评论中指出的那样,WHATWG规范基于IE5 +的拖放实现,这种实现早于多点触控设备.(在撰写本文时,没有主要的多点触控浏览器实现HTML拖放.)在"单触"上下文中,可以轻松地存储对当前拖动元素的全局引用dragstart.
其次,HTML拖放允许您跨多个文档拖动元素.这是真棒,但它也意味着提供对元素的引用被拖动每一个dragenter,dragover或dragleave事件就没有意义; 您不能在不同的文档中引用元素.无论拖动源自同一文档还是不同文档,这些事件的工作方式都是API的优势.
但是无法向所有拖动事件提供序列化信息,除非通过dataTransfer.types(如我的工作解决方案答案中所述),在API中是一个明显的遗漏.我已经向 WHATWG 提交了拖拽事件中的公共数据提案,我希望你能表达你的支持.
(非常不优雅)的解决方案是将选择器存储为对象中的一种数据dataTransfer.这是一个例子:http://jsfiddle.net/TrevorBurnham/eKHap/
这里的活动线是
e.dataTransfer.setData('text/html', 'foo');
e.dataTransfer.setData('draggable', '');
Run Code Online (Sandbox Code Playgroud)
然后在dragover和dragenter事件中,e.dataTransfer.types包含字符串'draggable',这是确定拖动哪个元素所需的ID.(请注意,浏览器显然需要为识别的MIME类型设置数据text/html,以便使其正常工作.在Chrome和Firefox中测试.)
这是一个丑陋,丑陋的黑客,如果有人能给我一个更好的解决方案,我会高兴地给予他们赏金.
更新:值得补充的一点值得注意的是,除了不优雅之外,规范还规定所有数据类型都将转换为小写ASCII.因此请注意,涉及大写字母或unicode的选择器将会中断.Jeffery的解决方案回避了这个问题.
鉴于当前的规范,我认为没有任何解决方案不是“黑客”。请愿WHATWG 是解决此问题的一种方法:-)
扩展“(非常不雅的)解决方案”(演示):
创建当前被拖动的所有元素的全局散列:
var dragging = {};
Run Code Online (Sandbox Code Playgroud)在dragstart处理程序中,为元素分配一个拖动 ID(如果它还没有),将元素添加到全局哈希,然后将拖动 ID 添加为数据类型:
var dragId = this.dragId;
if (!dragId) {
dragId = this.dragId = (Math.random() + '').replace(/\D/g, '');
}
dragging[dragId] = this;
e.dataTransfer.setData('text/html', dragId);
e.dataTransfer.setData('dnd/' + dragId, dragId);
Run Code Online (Sandbox Code Playgroud)在dragenter处理程序中,在数据类型中找到拖动 ID,并从全局哈希中检索原始元素:
var types = e.dataTransfer.types, l = types.length, i = 0, match, el;
for ( ; i < l; i++) {
match = /^dnd\/(\w+)$/.exec(types[i].toLowerCase());
if (match) {
el = dragging[match[1]];
// do something with el
}
}
Run Code Online (Sandbox Code Playgroud)如果您dragging对自己的代码保留哈希私有,则第三方代码将无法找到原始元素,即使他们可以访问拖动 ID。
这假设每个元素只能被拖动一次;使用多点触控我想可以使用不同的手指多次拖动相同的元素......
更新:为了允许在同一个元素上进行多次拖动,我们可以在全局散列中包含一个拖动计数:http : //jsfiddle.net/jefferyto/eKHap/2/
要检查它是否是一个文件,请使用:
e.originalEvent.dataTransfer.items[0].kind
Run Code Online (Sandbox Code Playgroud)
要检查类型,请使用:
e.originalEvent.dataTransfer.items[0].type
Run Code Online (Sandbox Code Playgroud)
即我只想允许一个文件 jpg、png、gif、bmp
var items = e.originalEvent.dataTransfer.items;
var allowedTypes = ["image/jpg", "image/png", "image/gif", "image/bmp"];
if (items.length > 1 || items["0"].kind != "file" || items["0"].type == "" || allowedTypes.indexOf(items["0"].type) == -1) {
//Type not allowed
}
Run Code Online (Sandbox Code Playgroud)
参考: https: //developer.mozilla.org/it/docs/Web/API/DataTransferItem