Предотвратить * касание * прокрутки родительского элемента, когда положение прокрутки внутреннего элемента достигает верха / низа? - PullRequest
0 голосов
/ 04 августа 2020

Решения в вопросе с аналогичным названием работают для колесика мыши прокрутки, но они не работают при прокрутке с использованием сенсорных событий, таких как на мобильных устройствах.

Например , поначалу может показаться, что ответ с самым высоким рейтингом можно просто использовать с событиями касания вместо событий колесика мыши, примерно так:

  public touchStart(event: TouchEvent) {
    this.lastTouchY = event.touches[0].pageY;
  }

  public touchMove(event: TouchEvent, scrollElement: HTMLElement) {
    const offsetY = this.lastTouchY
      ? this.lastTouchY - event.touches[0].pageY : 0;
    const isScrollingUp = offsetY < 0;
    const isScrollingDown = offsetY > 0;

    const scrollTop = scrollElement.scrollTop;
    const scrollHeight = scrollElement.scrollHeight;

    const elementHeightStr = window.getComputedStyle(scrollElement, null)
      .getPropertyValue("height");
    const innerHeight = parseInt(elementHeightStr.slice(0, -2));

    const isPastBottom = isScrollingDown && offsetY > scrollHeight - innerHeight - scrollTop;
    const isPastTop = isScrollingUp && -offsetY > scrollTop;

    if (isPastBottom || isPastTop) {
      event.stopPropagation();
      event.preventDefault();
      event.returnValue = false;
      return false;
    }
  }

Этот код правильно пытается предотвратить touchmove при прокрутке мимо верхней и нижней части элемента, но браузер (Google Chrome) игнорирует его, выдавая ошибку: [Intervention] Ignored attempt to cancel a touchmove event with cancelable=false, for example because scrolling is in progress and cannot be interrupted. (Обратите внимание, что эта ошибка возникает независимо от того, является ли touchmove пассивным или непассивным прослушивателем событий )

Конечно, это проблема, потому что ошибка описывает всю суть: текущая прокрутка должна быть прервана, чтобы не прокручивался родительский элемент.

Другой Все предлагаемые решения имеют схожие характеристики, насколько я могу судить:

  • Плагин Mousewheel делает n не работает для событий касания
  • Свойства CSS overscroll еще не поддерживаются на всех платформах
  • Изменение scrollTop, похоже, не дает желаемого эффекта
  • Директивы AngularJS, похоже, по-прежнему имеют проблему игнорирования отмены события
  • Реструктуризация HTML и CSS, чтобы избежать любого возможного распространения прокрутки, является непрактичным ограничением дизайна
  • et c.

Это это возможно решить эту проблему, вручную реализовав сенсорную прокрутку, что-то вроде:

  public touchStart(event: TouchEvent, scrollElement: HTMLElement) {
    this.lastTouchY = event.touches[0].pageY;
    this.lastScrollTop = scrollElement.scrollTop;
  }

  public touchMove(event: TouchEvent, scrollElement: HTMLElement) {
    event.stopPropagation();
    event.preventDefault();
    event.returnValue = false;
    if (this.lastScrollTop == null) {
      return false;
    }
    const offsetY = this.lastTouchY
      ? this.lastTouchY - event.touches[0].pageY : 0;

    scrollElement.scrollTop = this.lastScrollTop + offsetY;

    return false;
  }

Однако это проигрывает ряд обычных сенсорных функций, таких как скорость прокрутки. Хотя это тоже возможно повторно реализовать, в конечном итоге кажется очень неправильным повторно реализовать стандартное сенсорное взаимодействие исключительно для решения этой проблемы.

Тем не менее, безусловно, должен быть разумный способ сделать это. Какой наиболее разумный способ запретить событиям касания прокручивать родительский элемент, когда внутренний элемент находится вверху или внизу?

...