支持在画布上滚动和拖动动作

时间:2016-05-11 19:51:18

标签: javascript scroll drag-and-drop cross-browser touch

我有一个javascript circuit simulator,您可以通过拖动大门来编辑电路。有时电路变得非常大,因此它所绘制的画布元素超出了浏览器的视口并且滚动变得必要。

当带触摸屏的用户在屏幕上滑动手指时,我希望在电路元素上开始的幻灯片被解释为拖动。但是,从空白空间开始的幻灯片(由我的自定义逻辑确定是否显示在画布上)应该被解释为滚动。

如何让拖动和滚动行为和谐相处?我怎么做没有很好地模拟浏览器常用的滚动行为?用户讨厌滚动时w.r.t.本土行为。

(额外奖励:我如何在不改变通常的滚动行为的同时仍然阻止滚动触发导航动作[例如在Android上拉下来时已经在页面顶部重新加载]它])

我只是在我希望画布控制并显示拖动时才尝试调用touchEvent.preventDefault。滚动条出现后立即停止运行(浏览器发送触摸,但随后立即取消)。 CSS属性touch-action也可能有用,但我还没有尝试过很多。

1 个答案:

答案 0 :(得分:0)

我最终使用的解决方法是阻止div。

对于画布中的每个可拖动元素,我在该元素的位置上添加了一个touch-action: noneopacity: 0position: absolute的div。当用户触摸其中一个阻挡div时,滚动被阻止而不会干扰拖动事件。

setBlockers(blockers, overrideCursorStyle) {
    // ensure enough blocker divs exist
    while (this._blockerDivs.length < blockers.length) {
        let blockerDiv = document.createElement('div');
        blockerDiv.style.touchAction = 'none';
        blockerDiv.style.position = 'absolute';
        blockerDiv.style.opacity = 0;
        this._parentElement.appendChild(blockerDiv);
        this._blockerDivs.push(blockerDiv);
    }

    // reposition blocker divs
    for (let i = 0; i < blockers.length; i++) {
        let s = this._blockerDivs[i].style;
        let {x, y, w, h, cursor} = blockers[i];
        [s.left, s.top, s.width, s.height] = [x, y, w, h].map(e => e + "px");
        s.cursor = overrideCursorStyle || cursor || 'auto';
        s.display = 'inline';
    }

    // hide unused blocker divs
    for (let i = blockers.length; i < this._blockerDivs.length; i++) {
        this._blockerDivs[i].style.display = 'none';
    }
}

这适用于Chrome,适用于iOS上的Safari,但不适用于Firefox(不支持触摸操作:无)。