在 Chrome Android 上阻止 pointcancel 事件触发而不禁用触摸滚动?

use*_*947 11 javascript android google-chrome pointer-events

我在可滚动区域中有一堆子 div,如下所示:

<div style='overflow: scroll;'>
    <div id='a' />
    <div id='b' />
    <div id='c' />
    ...
</div>
Run Code Online (Sandbox Code Playgroud)

我监听每个子项上的pointerdown 事件,当事件触发时,我在文档上设置pointermove 处理程序。例如:

const pointerdownHandle = e => {
    e.target.releasePointerCapture(e.pointerId)
    document.addEventListener('pointermove', pointermoveHandle)
    document.addEventListener('pointerup', pointerupHandle)
}

const pointermoveHandle = e => { ... }

const pointerupHandle = {
    document.removeEventListener('pointermove', pointermoveHandle)
    document.removeEventListener('pointerup', pointerupHandle)  
}

document.getElementById('a').addEventListener('pointerdown', pointerdownHandle)
Run Code Online (Sandbox Code Playgroud)

这在桌面和 iOS Safari 上都非常有效。然而在 Android Chrome 上,pointercancel 事件几乎立即触发,从而破坏了一切。

这似乎是预期的行为: “当浏览器确定不可能再有任何指针事件时,将触发pointercancel事件,或者如果在触发pointerdown事件后,然后使用指针通过平移来操作视口,缩放或滚动。”

推荐的解决方案是将 css 属性“touch-action: none”应用于父元素。这有效。但不幸的是,这也会中断滚动,因为现在触摸操作被忽略。

我尝试在pointerdown事件触发后以编程方式应用css属性,但这不起作用。将 PreventDefault / stopPropagation 添加到pointermoveHandle 也不会。

有人能解决这个问题吗?如何在不禁用父元素滚动的情况下阻止 pointcancel 事件触发?

(我意识到我可以依靠触摸事件,但是支持pointerenter和pointerleave的指针事件使用起来更加简单和干净......)

ami*_*itp 4

您正在使用releasePointerCapture,但我认为您可能想做完全相反的事情。指针捕获将移动事件定向到您的元素,这样您就不必在 上放置事件处理程序document

即使我在其他地方使用指针事件,我也必须使用一次触摸事件来取消滚动。我无法弄清楚如何使用指针事件来取消滚动。

function makeDraggable(element) {
    let pos = {x: 0, y: 0}
    let dragging = false
    
    const stopScrollEvents = (event) => {
        event.preventDefault()
    }
        
    const pointerdownHandle = (event) => {
        dragging = {dx: pos.x - event.clientX, dy: pos.y - event.clientY}
        element.classList.add('dragging')
        element.setPointerCapture(event.pointerId)
    }
    
    const pointerupHandle = (event ) => {
        dragging = null
        element.classList.remove('dragging')
    }
    
    const pointermoveHandle = (event) => {
        if (!dragging) return
        pos.x = event.clientX + dragging.dx
        pos.y = event.clientY + dragging.dy
        element.style.transform = `translate(${pos.x}px, ${pos.y}px)`
    }
    
    element.addEventListener('pointerdown', pointerdownHandle)
    element.addEventListener('pointerup', pointerupHandle)
    element.addEventListener('pointercancel', pointerupHandle)
    element.addEventListener('pointermove', pointermoveHandle)
    element.addEventListener('touchstart', stopScrollEvents)
}

for (let element of document.querySelectorAll("#draggable-children > div")) {
    makeDraggable(element)
}
Run Code Online (Sandbox Code Playgroud)
#draggable-children {
    width: 100%;
    height: 100%;
    min-height: 5em;
    background: #eee;
    border: 1px solid black;
}

#draggable-children > div {
    width: 5em;
    height: 1.5em;
    background: #88a;
    border: 1px solid black;
    cursor: grab;
}

#draggable-children > div.dragging {
    width: 5em;
    height: 1.5em;
    background: #aa8;
    border: 1px solid black;
    cursor: grabbing;
}
Run Code Online (Sandbox Code Playgroud)
<div id="draggable-children">
    <div></div>
    <div></div>
    <div></div>
</div>
Run Code Online (Sandbox Code Playgroud)