繁体   English   中英

HTML5 Drag'n'Drop - 在iOS 12.1.2上无效(Safari和Chrome)

[英]HTML5 Drag'n'Drop - Not Working on iOS 12.1.2 (Safari and Chrome)

背景

我有一个可以通过拖放进行排序的列表。 它可以在桌面浏览器和Android上的Chrome上完美运行。 但是,它在iOS 12.1.2(iPhone 8)上的Safari和Chrome上根本不起作用。

现行守则

请参阅下面的代码段,以及便于移动测试: https//codepen.io/Kelderic/pen/KJMRgb

 var dragging = null; document.addEventListener('dragstart', function(event) { var target = getLI(event.target); dragging = target; event.dataTransfer.setData('text/plain', null); event.dataTransfer.setDragImage(self.dragging, 0, 0); }); document.addEventListener('dragover', function(event) { event.preventDefault(); var target = getLI(event.target); var bounding = target.getBoundingClientRect() var offset = bounding.y + (bounding.height / 2); if (event.clientY - offset > 0) { target.style['border-bottom'] = 'solid 4px blue'; target.style['border-top'] = ''; } else { target.style['border-top'] = 'solid 4px blue'; target.style['border-bottom'] = ''; } }); document.addEventListener('dragleave', function(event) { var target = getLI(event.target); target.style['border-bottom'] = ''; target.style['border-top'] = ''; }); document.addEventListener('drop', function(event) { event.preventDefault(); var target = getLI(event.target); if (target.style['border-bottom'] !== '') { target.style['border-bottom'] = ''; target.parentNode.insertBefore(dragging, event.target.nextSibling); } else { target.style['border-top'] = ''; target.parentNode.insertBefore(dragging, event.target); } }); function getLI(target) { while (target.nodeName.toLowerCase() != 'li' && target.nodeName.toLowerCase() != 'body') { target = target.parentNode; } if (target.nodeName.toLowerCase() == 'body') { return false; } else { return target; } } 
 ul.sorting { padding: 0; margin: 0; list-style: none; max-height: 300px; overflow-y: auto; box-shadow: inset 0 0 3px 1px rgba(0, 0, 0, 0.2); } ul.sorting li { padding: 10px; border-bottom: 1px solid black; user-select: none; cursor: move; } ul.sorting li:last-child { border-bottom: none; } 
 <ul class="sorting"> <li draggable="true" style="user-drag:element;">List Item 15</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 2</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 3</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 4</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 5</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 6</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 7</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 8</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 9</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 10</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 11</li> <li draggable="true" style="-webkit-user-drag:element;">List Item 12</li> </ul> 

iOS上的行为视频

https://imgur.com/a/I8hzPxC (尺寸太大,无法直接嵌入)

为什么这不适用于iOS? 我甚至无法启动dragstart事件。 在Android Chrome上,longpress会触发dragstart

我的后备想法是使用touchstarttouchend进行长按,然后创建我自己的绝对定位的ghost元素并手动拖动它。 drag*事件应该正常工作时,这是很多额外的代码。

我错过了什么吗?

编辑

移动Safari中的LI元素将ondragstart事件作为其原型的一部分。 问题是要解雇它。

此外,根据caniuse,移动Safari应该支持这一点。 但是,caniuse也表示Android Chrome不支持,但事实并非如此。

过去一周我在这个主题上做了很多研究,我做了很多测试和调试。 我发现iOS支持拖动事件,但iOS不会触发它们。 (截至iOS 12)

如果您在iOS Safari上测试网页,您会看到所有HTML元素都有ondragstart附加到他们的原型。 阻力事件就在那里。 它们永远不会被触发。

其他人也遇到过这个问题。 由于此错误支持,Event Modernizer 无法检测拖放支持。

另外,我挖掘了Safari文档, 发现了这个

iOS注意:虽然不支持拖放,但您可以生成...

它说“支持”,但在下面,有一个事件表,显示drag并说它不是“生成”。

这意味着caniuse目前是错误的,需要更新。


直接回答问题

代码不能单独工作,因为Apple选择不触发拖动事件。

不幸的是我没有iOS12的设备(我的设备不支持它),我无法测试它。 而且我不知道为什么iOS / Apple支持写道他们在iOS 11.2和新设备上支持这些事件它不受支持。

替代解决方法

通过此解决方法,您将获得适用于所有现代设备和浏览器的解决方案。 最好等待iOS / Apple的支持。

dragstartdragoverdragleavedrop events不适用于所有触控设备。

您必须为触摸事件使用适当的事件名称,例如:

  • touchstart
  • touchend
  • touchcancel
  • touchmove

阅读有关此事件的文档

为了为基于触摸的用户界面提供高质量的支持,触摸事件提供了在触摸屏或触控板上解释手指(或触控笔)活动的能力。

触摸事件接口是相对低级的API,可用于支持特定于应用程序的多点触摸交互,例如双指手势。 当手指(或触笔)首先接触接触表面时,多触摸交互开始。 其他手指随后可以触摸表面并且可选地在触摸表面上移动。 当手指从表面移除时,相互作用结束。 在此交互期间,应用程序在开始,移动和结束阶段接收触摸事件。

触摸事件类似于鼠标事件,除了它们支持同时触摸和触摸表面上的不同位置。 TouchEvent界面封装了当前活动的所有触摸点。 Touch界面代表单个触摸点,包括诸如触摸点相对于浏览器视口的位置之类的信息。

不幸的是,事件touchentertouchleave已从规范中删除,因此,如果您需要它,那么您必须使用document.elementFromPoint()编写一个解决方法,如下所示:

document.addEventListener('touchmove', function(e)
{
    var touch = e.touches[0],
        elementFromPoint = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset);

    if(elem == elementFromPoint) //elem is your element which was entered
    {
        //your code for touchenter event
    }
    else //the code for touchleave event
});

也许对于其他一些移动设备和他们的浏览器,你将需要使用polyfills( 12 ),这使得移动(触摸)设备HTML5拖放支持。

我在这里分叉你的codepen测试用例: https ://codepen.io/bobacus/pen/MLjZMg

我想知道是否需要将侦听器添加到<li>元素中,因此更改了一些代码:

listEl = document.getElementById('my_list');
for (var i = 0; i < listEl.children.length; i ++) {
    itemEl = listEl.children[i];
    itemEl.addEventListener('dragstart', function(event) {
      dragging = getLI(event.target);
      if (dragging) {
          event.dataTransfer.setData('text/plain', null);
          event.dataTransfer.setDragImage(dragging, 0, 0);
      }
    });
}

但那没用。

我尝试了一些不同的东西,但最终在Safari中使用的是添加这里描述的polyfill: https//www.codeproject.com/Articles/1091766/Add-support-for-standard-HTML-Drag-and -drop-OPERAT

我将其添加到HTML代码段的顶部:

<script src="http://bernardo-castilho.github.io/DragDropTouch/DragDropTouch.js"></script>

我希望这是有帮助的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM