触摸移动卡住了,尝试取消touchmove被忽略。

74

我正在尝试在触摸滑块上处理触摸事件,但是我一直收到以下错误:

Ignored attempt to cancel a touchmove event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.

我不确定是什么原因导致了这个问题,我刚刚开始接触触摸事件,并且似乎无法解决这个问题。

这里是处理触摸事件的代码:

Slider.prototype.isSwipe = function(threshold) {
    return Math.abs(deltaX) > Math.max(threshold, Math.abs(deltaY));
}


Slider.prototype.touchStart = function(e) {

    if (this._isSliding) return false;

      touchMoving = true;
      deltaX = deltaY = 0;

    if (e.originalEvent.touches.length === 1) {

        startX = e.originalEvent.touches[0].pageX;
        startY = e.originalEvent.touches[0].pageY;

        this._$slider.on('touchmove touchcancel', this.touchMove.bind(this)).one('touchend', this.touchEnd.bind(this));

        isFlick = true;

        window.setTimeout(function() {
            isFlick = false;
        }, flickTimeout);
    }
}


Slider.prototype.touchMove = function(e) {

    deltaX = startX - e.originalEvent.touches[0].pageX;
    deltaY = startY - e.originalEvent.touches[0].pageY;

    if(this.isSwipe(swipeThreshold)) {
        e.preventDefault();
        e.stopPropagation();
        swiping = true;
    }
    if(swiping) {
        this.slide(deltaX / this._sliderWidth, true)
    }
}


Slider.prototype.touchEnd = function(e) {

    var threshold = isFlick ? swipeThreshold : this._sliderWidth / 2;

    if (this.isSwipe(threshold)) {
        deltaX < 0 ? this.prev() : this.next();
    }
    else {
        this.slide(0, !deltaX);
    }

    swiping = false;

    this._$slider.off('touchmove', this.touchMove).one(transitionend, $.proxy(function() {
        this.slide(0, true);
        touchMoving = false;
    }, this));
}

您可以在此处查看实际的滑块

如果您快速地滑动,它会导致错误并有时会在滑动中间卡住。仍然无法理解为什么它不能正常工作。非常感谢任何帮助/见解。不确定我做错了什么。

6个回答

50

此事件必须是可取消的(cancelable)。添加一个if语句可以解决这个问题。

if (e.cancelable) {
   e.preventDefault();
}

在你的代码中,你应该把它放在这里:

if (this.isSwipe(swipeThreshold) && e.cancelable) {
   e.preventDefault();
   e.stopPropagation();
   swiping = true;
}

15

我知道这是一篇旧帖子,但是我在尝试解决这个问题时遇到了很多麻烦,最终我解决了,所以我想分享一下。

我的问题是我在ontouchstart中添加了一个事件监听器,并在ontouchend函数中将其删除 - 类似于这样

function onTouchStart() {
  window.addEventListener("touchmove", handleTouchMove, {
    passive: false
  });
}

function onTouchEnd() {
  window.removeEventListener("touchmove", handleTouchMove, {
    passive: true
  });
}

function handleTouchMove(e) {
  e.preventDefault();
}

由于某种原因,这样添加或删除它会导致事件随机无法被取消。为了解决这个问题,我保持监听器处于活动状态,并切换一个布尔变量来确定是否应该阻止事件——类似于这样:

let stopScrolling = false;

window.addEventListener("touchmove", handleTouchMove, {
  passive: false
});

function handleTouchMove(e) {
  if (!stopScrolling) {
    return;
  }
  e.preventDefault();
}

function onTouchStart() {
  stopScrolling = true;
}

function onTouchEnd() {
  stopScrolling = false;
}

实际上我使用的是React,所以我的解决方案涉及设置状态,但我将其简化为更通用的解决方案。希望这能帮助到某些人!


12

我有过类似的问题,解决方法就是在 touchend 函数里返回 true,这样警告就消失了。


12
这里什么也没改变。 - Eric
6
在这个语句中,我在 if 语句中添加了 e.cancelable,然后再尝试调用 e.preventDefault() - ravo10

8

在Chrome浏览器中,当您正在滚动时,在touchmove上调用preventDefault功能不能正常工作。为了防止性能问题,您不能中断滚动。

尝试从touchstart中调用preventDefault(),一切都应该没问题。


4
我得到的内容是:“尝试取消touchstart事件被忽略了。” - Curtis
事件监听器按附加顺序调用。@Curtis,也许您正在添加touchstart事件处理程序之前调用preventDefault()的事件处理程序,而Chrome已经开始逻辑(滚动,捏缩放)以防止取消touchstart/touchmove事件。 - dotnetCarpenter

3
请移除e.preventDefault(),因为touchmove事件的event.cancelable属性为false,所以你不能调用这个方法。

0
如果它是一张图片,你可以在CSS中将'touch-action'设置为none。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接