简体   繁体   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)

Background 背景

I have a list that is sortable via drag and drop. 我有一个可以通过拖放进行排序的列表。 It works perfectly on desktop browser, and on Chrome on Android. 它可以在桌面浏览器和Android上的Chrome上完美运行。 However, it didn't work at all on Safari and Chrome on iOS 12.1.2 (iPhone 8). 但是,它在iOS 12.1.2(iPhone 8)上的Safari和Chrome上根本不起作用。

Current Code 现行守则

See snippet below, and also for easy mobile testing: https://codepen.io/Kelderic/pen/KJMRgb 请参阅下面的代码段,以及便于移动测试: 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> 

Video of Behavior on iOS iOS上的行为视频

https://imgur.com/a/I8hzPxC (Size is too large for direct embed) https://imgur.com/a/I8hzPxC (尺寸太大,无法直接嵌入)

Question

Why is this not working on iOS? 为什么这不适用于iOS? I can't even get the dragstart event to fire. 我甚至无法启动dragstart事件。 On Android Chrome, a longpress fires the dragstart . 在Android Chrome上,longpress会触发dragstart

My fallback idea is to make a longpress using touchstart and touchend , then create my own absolutely positioned ghost element and drag it around manually. 我的后备想法是使用touchstarttouchend进行长按,然后创建我自己的绝对定位的ghost元素并手动拖动它。 That is a lot of extra code when the drag* events should just work. drag*事件应该正常工作时,这是很多额外的代码。

Am I missing something? 我错过了什么吗?

Edit 编辑

LI elements in mobile Safari have an ondragstart event as part of their prototype. 移动Safari中的LI元素将ondragstart事件作为其原型的一部分。 The question is getting it to fire. 问题是要解雇它。

Also, according to caniuse, mobile Safari should support this. 此外,根据caniuse,移动Safari应该支持这一点。 However, caniuse also shows Android Chrome as not supporting, which isn't true. 但是,caniuse也表示Android Chrome不支持,但事实并非如此。

I have done a lot of research over the past week on this topic, and I've done a lot of testing and debugging. 过去一周我在这个主题上做了很多研究,我做了很多测试和调试。 What I have discovered is that iOS supports drag events, but iOS doesn't trigger them. 我发现iOS支持拖动事件,但iOS不会触发它们。 (As of iOS 12) (截至iOS 12)

If you test webpage on iOS Safari, you'll see that all HTML elements have ondragstart attached to their prototype. 如果您在iOS Safari上测试网页,您会看到所有HTML元素都有ondragstart附加到他们的原型。 The drag events are all there. 阻力事件就在那里。 They just never get triggered. 它们永远不会被触发。

Others have run into this issue as well. 其他人也遇到过这个问题。 Event Modernizer doesn't detect Drag and Drop support because of this false support. 由于此错误支持,Event Modernizer 无法检测拖放支持。

Additionally, I dug through the Safari docs, and found this : 另外,我挖掘了Safari文档, 发现了这个

iOS Note: Although drag and drop are not supported, you can produce... iOS注意:虽然不支持拖放,但您可以生成...

It says "supported", but immediately below, there is an event table, which shows drag and says that it isn't "Generated". 它说“支持”,但在下面,有一个事件表,显示drag并说它不是“生成”。

This means that caniuse is currently wrong, and needs updated. 这意味着caniuse目前是错误的,需要更新。


Direct Answer To Question 直接回答问题

The code is not working solely because Apple has chosen not to trigger drag events. 代码不能单独工作,因为Apple选择不触发拖动事件。

Unfortunately I do not have a device with iOS12 (my device does not suppot it) and I can not test it. 不幸的是我没有iOS12的设备(我的设备不支持它),我无法测试它。 And I do not know why iOS/Apple support writes that they support this events in iOS 11.2 and on your new device it is not supported. 而且我不知道为什么iOS / Apple支持写道他们在iOS 11.2和新设备上支持这些事件它不受支持。

Alternative workaround 替代解决方法

With this workaround you will get a solution for all modern devices and browsers. 通过此解决方法,您将获得适用于所有现代设备和浏览器的解决方案。 It is better than to wait for support from iOS/Apple. 最好等待iOS / Apple的支持。

dragstart , dragover , dragleave , drop events do not work on all touch devices. dragstartdragoverdragleavedrop events不适用于所有触控设备。

You have to use the apropriate event names for your touch events like: 您必须为触摸事件使用适当的事件名称,例如:

  • touchstart
  • touchend
  • touchcancel
  • touchmove

Read the documentation about this events. 阅读有关此事件的文档

In order to provide quality support for touch-based user interfaces, touch events offer the ability to interpret finger (or stylus) activity on touch screens or trackpads. 为了为基于触摸的用户界面提供高质量的支持,触摸事件提供了在触摸屏或触控板上解释手指(或触控笔)活动的能力。

The touch events interfaces are relatively low-level APIs that can be used to support application specific multi-touch interactions such as a two-finger gesture. 触摸事件接口是相对低级的API,可用于支持特定于应用程序的多点触摸交互,例如双指手势。 A multi-touch interaction starts when a finger (or stylus) first touches the contact surface. 当手指(或触笔)首先接触接触表面时,多触摸交互开始。 Other fingers may subsequently touch the surface and optionally move across the touch surface. 其他手指随后可以触摸表面并且可选地在触摸表面上移动。 The interaction ends when the fingers are removed from the surface. 当手指从表面移除时,相互作用结束。 During this interaction, an application receives touch events during the start, move and end phases. 在此交互期间,应用程序在开始,移动和结束阶段接收触摸事件。

Touch events are similar to mouse events except they support simultaneous touches and at different locations on the touch surface. 触摸事件类似于鼠标事件,除了它们支持同时触摸和触摸表面上的不同位置。 The TouchEvent interface encapsulates all of the touch points that are currently active. TouchEvent界面封装了当前活动的所有触摸点。 The Touch interface, which represents a single touch point, includes information such as the position of the touch point relative to the browser viewport. Touch界面代表单个触摸点,包括诸如触摸点相对于浏览器视口的位置之类的信息。

Unfortunatelly, the events touchenter and touchleave were deleted from the specification and because of this if you need it then you have to write a workaround using document.elementFromPoint() like follows: 不幸的是,事件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
});

Maybe for some other mobile devices and their browsers you will need to use polyfills ( 1 , 2 ) which enable HTML5 drag drop support on mobile (touch) devices. 也许对于其他一些移动设备和他们的浏览器,你将需要使用polyfills( 12 ),这使得移动(触摸)设备HTML5拖放支持。

I forked your codepen test case here: https://codepen.io/bobacus/pen/MLjZMg 我在这里分叉你的codepen测试用例: https ://codepen.io/bobacus/pen/MLjZMg

I was wondering if the listeners needed to be added to the <li> elements, so changed some of the code: 我想知道是否需要将侦听器添加到<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);
      }
    });
}

But that didn't work. 但那没用。

I tried a few different things, but what finally got it to work in Safari was adding a polyfill described here: https://www.codeproject.com/Articles/1091766/Add-support-for-standard-HTML-Drag-and-Drop-operat 我尝试了一些不同的东西,但最终在Safari中使用的是添加这里描述的polyfill: https//www.codeproject.com/Articles/1091766/Add-support-for-standard-HTML-Drag-and -drop-OPERAT

I added this to the top of the HTML snippet: 我将其添加到HTML代码段的顶部:

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

I hope this is helpful. 我希望这是有帮助的。

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

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