停止触发pointercancel事件,而无需禁用Chrome Android上的触摸滚动?

rryofs0p  于 2023-01-28  发布在  Go
关注(0)|答案(1)|浏览(147)

我在一个可滚动区域中有一堆子div,类似于以下内容:

<div style='overflow: scroll;'>
    <div id='a' />
    <div id='b' />
    <div id='c' />
    ...
</div>

我监听每个子进程上的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)

这在桌面和iOS Safari上都很有效。然而在Android Chrome上,PointerCancel事件几乎立即触发,破坏了东西。
这似乎是the expected behaviour:“当浏览器确定不太可能再发生指针事件时,或者如果在触发pointerdown事件后,指针被用于通过平移、缩放或滚动来操纵视口,则触发pointercancel事件。”
建议的解决方案是应用css属性“touch-action:none”到父元素。这是有效的。但是不幸的是,这也会中断滚动,因为现在触摸操作被忽略了。
我试过在pointerdown事件触发后编程应用css属性,但这不起作用,在pointermoveHandle中添加preventDefault / stopPropagation也不起作用。
有人能解决这个问题吗?我怎样才能在不禁用父元素滚动的情况下阻止pointercancel事件的触发?
(我意识到我可以求助于触摸事件,但是指针事件支持pointerenter和pointerleave,使用起来要简单和干净得多。)

wwtsj6pe

wwtsj6pe1#

你正在使用releasePointerCapture,但我认为你可能想做的正好相反。指针捕获将move事件定向到你的元素,这样你就不必在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)
}
#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;
}
<div id="draggable-children">
    <div></div>
    <div></div>
    <div></div>
</div>

相关问题