提问人:Chris 提问时间:4/21/2023 最后编辑:Chris 更新时间:5/14/2023 访问量:560
使用 W3C PointerEvent API 并能够检测到双击?
Using W3C PointerEvent API and be able to detect a double click?
问:
编写一个丰富的 Web 应用程序,我需要支持所有类型的用户,有些使用鼠标,有些使用触摸屏(例如在移动设备上)。因此,W3C PointerEvent API 正是我处理用户交互所需要的。这很好用,除了一个重要情况:双击。
有几件事阻碍了:
- 没有像“”这样的(高级)事件,只有低级和可用。
pointerdblclick
pointerdown
pointerup
- 要解决此问题并自己计算双击,通常建议使用发出事件的属性并检查它是否具有值。但这个属性总是在我的情况下。
detail
2
0
- 但是,即使我自己跟踪这个数字也无法完美地工作,因为操作系统(以及用户可能的设置)正在定义最大延迟,即双击两次。
那么,当所有其他用户交互都是通过侦听 PointerEvents 来处理时,我该如何对鼠标双击或触摸双击做出反应呢?甚至可以以尊重双击延迟的操作系统设置的方式做到这一点吗?
注 1:我仍然必须能够检测到正常的点击(通过听 和 )以及拖拽(通过听 和 稍后)
注 2:我使用的是“纯”JavaScript 和现代浏览器,jQuery 是没有选择的。pointerdown
pointerup
pointerdown
pointermove
pointerup
答:
1赞
amitp
5/14/2023
#1
下面是一个可运行的示例,用于侦听用于拖动的低级指针事件和高级单击事件。当按下鼠标按钮、移动鼠标和释放按钮时,我们将收到一个事件。但我们可能想把它当作一种拖累。所以我有一个变量来检测是否有拖累。click
gotMoveEvent
// code based on https://www.redblobgames.com/making-of/draggable/
const messages = document.querySelector("figcaption");
const draggable = document.querySelector("circle");
let dragging = false;
let gotMoveEvent = false;
draggable.onpointerdown = (event) => {
if (event.button !== 0) return; // only drag on left click
draggable.classList.add("dragging"); // css feedback
event.currentTarget.setPointerCapture(event.pointerId); // capture
dragging = true;
gotMoveEvent = false;
messages.innerText = "Click or drag?";
}
draggable.onpointerup = (event) => {
dragging = false;
draggable.classList.remove("dragging"); // css feedback
}
draggable.onpointercancel = draggable.onpointerup;
draggable.onpointermove = (event) => {
if (!dragging) return;
gotMoveEvent = true;
messages.innerText = "Dragging";
let p = convertPixelToSvgCoord(event);
draggable.setAttribute("transform", `translate(${p.x},${p.y})`);
}
draggable.onclick = (event) => {
if (gotMoveEvent) {
messages.innerText = "Ignoring click event because we were dragging";
event.preventDefault();
return;
}
messages.innerText = "Got click";
}
draggable.ondblclick = (event) => {
// maybe: check for gotMoveEvent here too?
messages.innerText = "Got dblclick";
}
/** Convert from event coordinate space (on the page) to SVG coordinate
* space (within the svg, honoring responsive resizing, width/height,
* and viewBox) */
function convertPixelToSvgCoord(event, relativeTo=event.currentTarget.ownerSVGElement) {
// if relativeTo is the <svg> then its ownerSVGElement is null, so we want to point back to the <svg>
// but otherwise we assume it's a child of <svg> and we want to find the <svg>
let p = (relativeTo.ownerSVGElement ?? relativeTo).createSVGPoint();
p.x = event.clientX;
p.y = event.clientY;
return p.matrixTransform(relativeTo.getScreenCTM().inverse());
}
.draggable { fill: hsl(0 50% 50%); cursor: grab; }
.draggable.dragging { fill: hsl(200 50% 50%); cursor: grabbing; user-select: none; }
<figure>
<figcaption>Drag or click</figcaption>
<svg viewBox="-200 -50 400 100" style="background:hsl(60 5% 95%)">
<circle class="draggable" r="20" />
</svg>
</figure>
评论
pointerdown
pointerup
click
dblclick
dblclick