web-dev-qa-db-ja.com

タッチムーブがスタックするタッチムーブをキャンセルする試みを無視する

タッチスライダーのタッチイベントをいじっていますが、次のエラーが発生し続けます。

たとえば、スクロールが進行中で中断できないため、cancellable = falseでtouchmoveイベントをキャンセルしようとする試みを無視しました。

この問題の原因はわかりませんが、タッチイベントを扱うのは初めてで、この問題を解決できないようです。

タッチイベントを処理するコードは次のとおりです。

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));
}

実際のスライダーここのペンを見つけることができます。

十分に速くスワイプすると、エラーがスローされ、スワイプの途中でスタックすることがあります。なぜそれが機能していないのか、私の頭を包むことはできません。どんな助け/洞察も大歓迎です。何が間違っているのかわかりません。

36
souporserious

イベントはcancelableでなければなりません。 ifステートメントを追加すると、この問題が解決します。

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

あなたのコードでそれをここに置くべきです:

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

この問題があり、やらなければならなかったのはreturn trueタッチエンドから警告が消えました。

11
Chet

アクティブにスクロールしているときにpreventDefaulttouchmoveを呼び出しても、Chromeでは機能しません。パフォーマンスの問題を防ぐために、スクロールを中断することはできません。

touchstartからpreventDefault()を呼び出そうとすると、すべて問題ありません。

6
MartinMoizard

私はこれが古い投稿であることを知っていますが、これを解決するために多くの問題を抱えていたので、共有したいと思いました。

私の問題は、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を使用していたので、私の解決策は状態の設定を必要としましたが、より一般的な解決策のためにそれを単純化しました。

3
Jeff Hernandez

Touchmoveの_event.cancelable_はfalseであるため、e.preventDefault()を削除してください。したがって、このメソッドを呼び出すことはできません。

2
mqliutie