我想做一些东西,允许用户从一个模式对话框中拖动元素,并将它们放在页面上. 因此,一旦用户开始拖动,我就会呼叫dialog.close().这在台式机上运行得很好,但在touch 式设备上,‘PointerMove’事件不会触发.

有关示例,请参阅下面的片段:

dialog.showModal();

button.addEventListener("pointerdown", () => {
    dialog.close();
});

container.addEventListener("pointermove", () => {
    console.log("move");
});
html, body, dialog, #container, #button {
  touch-action: none;
}

#container {
  width: 100px;
  height: 100px;
  background: red;
}

#button {
  width: 50px;
  height: 50px;
  background: green;
}
<div id="container">
  
</div>

<dialog id="dialog">
  Emulate a touch device using devtools and drag the green square to the red square.
  <div id="button">
  
  </div>
</dialog>

推荐答案

在触控设备上实现"拖放"功能时,你会面临两个问题:

直接操作设备导致隐式指针捕获

让用户通过touch 屏幕来平移和zoom 屏幕的设备被归类为"直接操作"设备.源自此类设备的指针事件受implicit pointer capture的限制,这意味着所有后续事件仅限于捕获初始pointerdown事件的元素.

9.4隐式指针捕获

实现平移和zoom 的直接操作交互的输入(如touch 屏上的touch 或指示笔)的行为应该与在调用任何Pointerdown侦听器之前在目标元素上调用setPointerCapture()完全相同.

要绕过这一限制并让红色方块接收来自绿色方块的指针事件,您可以拨打releasePointerCapture:

button.addEventListener("pointerdown", event => {
    dialog.close();
    event.target.releasePointerCapture(event.pointerId);
});

平移将取消指针事件

直接操纵设备依赖于用户在屏幕上拖动手指来平移(或滚动)页面.如果没有touch-action: none,您会发现对话框一关闭,移动手指就会导致页面滚动,这是prevents the pointermove event from firing:

4.1.3.3 suppress 指针事件流

当用户代理检测到指针不太可能继续产生事件时,它必须 suppress 指针事件流.以下任一场景均满足此条件(可能还有其他场景):

  • 该指针随后被用户代理用来操纵页面视区(例如,平移或zoom ).

正如您已经发现的,解决此问题的一种方法是使用touch-action,如果手势源自受影响的元素,则会阻止平移或zoom :

#button {
    touch-action: none;
}

Do not在文档中的所有元素上将touch-action设置为none,因为这将防止您的用户滚动页面,使其不可用.

Javascript相关问答推荐

如何使图像逐渐/平稳地响应(先减少宽度,然后减少高度)

IOS(React Native)中未找到模块SquareReaderSDK

如何在不指定宽度和高度的情况下显示来自网址的下一张图像

我可以后增量超过1(最好是内联)吗?

Angular material 表多个标题行映射

在HTML中使用脚本变量作为背景图像源

如何避免使用ajax在Vue 3合成API中重定向

如何指定1条记录1个表?

在JavaScript中,是否有一种方法可以创建自定义thable,在等待某些代码后自动触发它?

如何修复循环HTML元素附加函数中的问题?

如何为GrapesJS模板编辑器创建自定义撤销/重复按钮?

Cookie中未保存会话数据

如何使用JavaScript将文本插入空div

如何在ASP.NET中使用Google Charts API JavaScript将条形图标签显示为绝对值而不是负值

我怎么在JS里连续加2个骰子的和呢?

提交链接到AJAX数据结果的表单

JQuery Click事件不适用于动态创建的按钮

更新动态数据中对象或数组中的所有值字符串

第一项杀死下一项,直到数组长度在javascript中等于1

使用createBrowserRoutVS BrowserRouter的Reaction路由