Ily*_*nov 45 javascript javascript-events
我正在尝试在我的Web应用程序中开发一个简单的拖放UI.可以通过鼠标或手指拖动项目,然后将其放入多个放置区域中的一个.当项目拖放到放置区域(但尚未释放)时,该区域将突出显示,标记安全着陆位置.这对鼠标事件完全没问题,但我在iPhone/iPad上遇到了touchstart/touchmove/touchend系列.
问题是当调用项目的ontouchmove事件处理程序时,它event.touches[0].target始终指向原始HTML元素(项目)而不是当前在手指下的元素.此外,当用手指在某个放置区域上拖动某个项目时,touchmove根本不会调用该放置区域自己的处理程序.这实际上意味着我无法确定手指何时位于任何放置区域之上,因此无法根据需要突出显示它们.同时,在使用鼠标时,mousedown会正确触发光标下的所有HTML元素.
有些人确认它应该像那样工作,例如http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/: 对于那些你来自的人在正常的web设计世界中,在正常的mousemove事件中,目标属性中传递的节点通常是鼠标当前所在的节点.但在所有iPhone touch事件中,目标是对原始节点的引用.
问题:有没有办法确定手指下的实际元素(不是最初触及的元素,在许多情况下可能会有所不同)?
Gle*_*ard 46
这当然不是事件目标的工作方式.还有另一个DOM不一致,我们现在可能永远都会陷入困境,因为供应商在没有任何审查的情况下提出了闭门造车的扩展.
使用document.elementFromPoint来解决它.
document.elementFromPoint(event.clientX, event.clientY);
Run Code Online (Sandbox Code Playgroud)
JSP*_*P64 34
2010年接受的答案不再有效:touchmove没有clientX或clientY属性.(我猜它已经习惯了,因为答案有很多赞成,但目前还没有.)
目前的解决方案是
var myLocation = event.originalEvent.changedTouches[0];
var realTarget = document.elementFromPoint(myLocation.clientX, myLocation.clientY);
Run Code Online (Sandbox Code Playgroud)
经过测试和处理:
不适用于:
未测试:
use*_*859 15
尝试event.target.releasePointerCapture(event.pointerId)在指针向下处理程序中使用。
现在已经是 2022 年了,这是预期和指定的行为 - 它被称为“隐式指针捕获”
直接操作设备的行为应该与在调用任何 pointdown 侦听器之前在目标元素上调用 setPointerCapture 完全相同。可以使用 hasPointerCapture API(例如,在任何指针向下侦听器内)来确定是否发生了这种情况。
elementFromPoint 是一个可能的解决方案,但似乎您也可以使用releasePointerCapture,如以下演示所示。触摸并按住绿色 div 将获得其外部目标的鼠标移动事件,而红色 div 具有默认行为。
const outputDiv = document.getElementById('output-div');
const releaseDiv = document.getElementById('test-release-div');
const noreleaseDiv = document.getElementById('test-norelease-div');
releaseDiv.addEventListener('pointerdown', function(e) {
outputDiv.innerHTML = "releaseDiv-pointerdown";
if (e.target.hasPointerCapture(e.pointerId)) {
e.target.releasePointerCapture(e.pointerId);
}
});
noreleaseDiv.addEventListener('pointerdown', function(e) {
outputDiv.innerHTML = "noreleaseDiv-pointerdown";
});
document.addEventListener('pointermove', function(e) {
outputDiv.innerHTML = e.target.id;
});Run Code Online (Sandbox Code Playgroud)
<div id="output-div"></div>
<div id="test-release-div" style="width:300px;height:100px;background-color:green;touch-action:none;user-select:none">Touch down here and move around, this releases implicit pointer capture</div>
<div id="test-norelease-div" style="width:300px;height:100px;background-color:red;touch-action:none;user-select:none">Touch down here and move around, this doesn't release implicit pointer capture<div>Run Code Online (Sandbox Code Playgroud)
小智 6
我在 Android (WebView + Phonegap) 上遇到了同样的问题。我希望能够拖动元素并检测它们何时被拖动到某个其他元素上。出于某种原因,触摸事件似乎忽略了pointer-events属性值。
鼠:
pointer-events="visiblePainted"设置然后event.target将指向拖动的元素。pointer-events="none"设置然后event.target将指向拖动元素下的元素(我的拖动区域)这就是事情应该如何运作以及我们首先拥有该pointer-events属性的原因。
触碰:
event.target始终指向拖动的元素,无论pointer-events恕我直言错误的值如何。我的解决方法是创建我自己的拖动事件对象(鼠标和触摸事件的通用界面)来保存事件坐标和目标:
对于触摸事件,我使用:
DragAndDrop.prototype.getDragEventFromTouch = function (event) {
var touch = event.touches.item(0);
return {
screenX: touch.screenX,
screenY: touch.screenY,
clientX: touch.clientX,
clientY: touch.clientY,
pageX: touch.pageX,
pageY: touch.pageY,
target: document.elementFromPoint(touch.screenX, touch.screenY)
};
};
Run Code Online (Sandbox Code Playgroud)然后使用它进行处理(检查拖动的对象是否在我的拖动区域中)。出于某种原因document.elementFromPoint(),pointer-events即使在 Android 上似乎也尊重价值。
因此,当涉及到如何交互时,触摸事件具有不同的“哲学”:
这种差异来自这样一个事实,即不能在没有 touchstart 事件的情况下进行 touchmove,因为用户必须触摸屏幕才能开始此交互。使用鼠标,用户当然可以在整个屏幕上移动鼠标而无需按下按钮(mousedown 事件)
这就是为什么基本上我们不能希望使用触摸悬停效果之类的东西:
element:hover {
background-color: yellow;
}
Run Code Online (Sandbox Code Playgroud)
这就是为什么当用户用一根手指触摸屏幕时,第一个事件 (touchstart) 获取目标元素,随后的事件 (touchmove) 将保留对触摸开始的原始元素的引用。感觉不对,但有这种逻辑,您可能也需要原始目标信息。所以理想情况下,将来应该有(源目标和当前目标)可用。
因此,今天(2018 年)屏幕可以同时是鼠标和触摸的常见做法仍然是附加两个侦听器(鼠标和触摸),然后“标准化”事件坐标并使用上述浏览器 api 在这些坐标中查找元素:
// get coordinates depending on pointer type:
var xcoord = event.touches? event.touches[0].pageX : event.pageX;
var ycoord = event.touches? event.touches[0].pageY : event.pageY;
// get element in coordinates:
var targetElement = document.elementFromPoint(xcoord, ycoord);
// validate if this is a valid element for our case:
if (targetElement && targetElement.classList.contains("dropZone")) {
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22090 次 |
| 最近记录: |