Не дозволяйте горизонтальну прокрутку при прокручуванні вертикально (і навпаки)


17

У мене є список, з overflow-xі overflow-yвстановлено auto. Крім того, я налаштував прокрутку імпульсу, тому прокрутка на дотик добре працює в мобільному режимі webkit-overflow-scrolling: true.

Однак проблема полягає в тому, що я не можу зрозуміти, як відключити горизонтальну прокрутку при прокручуванні по вертикалі. Це призводить до по-справжньому поганого досвіду користувача, оскільки проведення вгору вліво або вправо призведе до того, що таблиця буде прокручуватися по діагоналі. Коли користувач прокручує вертикально, я абсолютно НЕ хочу, щоб прокручування було горизонтально, поки користувач не перестав прокручувати вертикально.

Я спробував таке:

JS:

offsetX: number;
offsetY: number;
isScrollingHorizontally = false;
isScrollingVertically = false;

//Detect the scrolling events
ngOnInit() {
    this.scrollListener = this.renderer.listen(
      this.taskRows.nativeElement,
      'scroll',
      evt => {
        this.didScroll();
      }
    );

    fromEvent(this.taskRows.nativeElement, 'scroll')
      .pipe(
        debounceTime(100),
        takeUntil(this.destroy$)
      )
      .subscribe(() => {
        this.endScroll();
    });
}

didScroll() {
    if ((this.taskRows.nativeElement.scrollLeft != this.offsetX) && (!this.isScrollingHorizontally)){
        console.log("Scrolling horizontally")
        this.isScrollingHorizontally = true;
        this.isScrollingVertically = false;
        this.changeDetectorRef.markForCheck();
    }else if ((this.taskRows.nativeElement.scrollTop != this.offsetY) && (!this.isScrollingVertically)) {
        console.log("Scrolling Vertically")
        this.isScrollingHorizontally = false;
        this.isScrollingVertically = true;
        this.changeDetectorRef.markForCheck();
    }
}

endScroll() {
    console.log("Ended scroll")
    this.isScrollingVertically = false;
    this.isScrollingHorizontally = false;
    this.changeDetectorRef.markForCheck();
}

HTML:

<div
    class="cu-dashboard-table__scroll"
    [class.cu-dashboard-table__scroll_disable-x]="isScrollingVertically"
    [class.cu-dashboard-table__scroll_disable-y]="isScrollingHorizontally"
>

CSS:

&__scroll {
  display: flex;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overflow-x: auto;
  will-change: transform;
  -webkit-overflow-scrolling: touch;

  &_disable-x {
     overflow-x: hidden;
  }

  &_disable-y {
    overflow-y: hidden;
  }
}

Але кожен раз, коли безліч I overflow-xабо overflow-yдо hiddenколи його прокручується, прокрутка буде глюк і перейти назад до вершини. Я також помітив, що webkit-overflow-scrolling: trueце причина, коли це відбувається, коли я його видаляю, поведінка, схоже, припиняється, але мені це абсолютно потрібно для прокрутки імпульсів у мобільних пристроях.

Як відключити горизонтальну прокрутку при прокручуванні вертикально?


Я не знаю, як виправити проблему прокрутки. Може, зробити крок назад і спробувати не допустити прокрутки однієї з двох осей? Поза темою: таблиці не призначені для дійсно малих екранів.
Joep Kockelkorn

У вашому коді відсутня фігурна дужка. Якщо ви додасте його як фрагмент, ви побачите повідомлення про помилку в консолі.
Разван Замфір

просто дурна ідея. чому б не використати два повзунки або власні повзунки для прокрутки?
Томас Людвіг

Пов'язана концепція: stackoverflow.com/questions/24594653/…
Джеймс Данн

Відповіді:


4

Спробуйте це

HTML
<div
  class="cu-dashboard-table__scroll-vertical"
>
  <div
    class="cu-dashboard-table__scroll-horizontal"
  >
    <!-- Scroll content here -->
  </div>
</div>


CSS
&__scroll {
  &-horizontal {
    overflow-x: auto;
    width: 100%;
    -webkit-overflow-scrolling: touch;
  }

  &-vertical {
    overflow-y: auto;
    height: 100%;
    -webkit-overflow-scrolling: touch;
  }
}

Замість використання одного діва для прокрутки, чому ви не використовуєте два? Один для X і один для Y


1
Чудова ідея! погано даю в цьому постріл.
Джош О'Коннор

1
Лол, я мушу сказати, що це геніальна ідея.
frodo2975

15

Як правило, для вашого дизайну погана практика потребує багатоосі прокрутки на мобільних пристроях, якщо, можливо, ви не показуєте великі таблиці даних. Коли це сказано, чому ви хочете це запобігти? Якщо користувач хоче прокрутити по діагоналі, це не здається мені кінцем світу. Деякі браузери, як-от Chrome на OSX, уже виконують те, що ви описуєте, за замовчуванням.

Якщо вам потрібна одновісна прокрутка, можливим рішенням може бути самостійне відстеження положення прокрутки за допомогою touchstartта touchmoveподій. Якщо встановити поріг перетягування нижче, ніж у веб-переглядача, ви, можливо, зможете робити свої файли css до того, як він почне прокручуватися, уникаючи сприйнятого глюку. Крім того, навіть якщо це все-таки глюкає, у вас є сенсорний старт і поточне місце дотику. Якщо ви записуєте початкове місце прокрутки вашого div, ви можете вручну прокрутити div до потрібного місця, щоб протидіяти його стрибку на вершину, якщо вам потрібно. Можливий алгоритм може виглядати так:

// Touchstart handler
if (scrollState === ScrollState.Default) {
    // Record position and id of touch
    touchStart = touch.location
    touchStartId = touch.id.
    scrollState = ScrollState.Touching

    // If you have to manually scroll the div, first store its starting scroll position:
    containerTop = $('.myContainer').scrollTop();
    containerLeft = $('.myContainer').scrollLeft();
}

// Touchmove handler - If the user has dragged beyond a distance threshold,
// do the css classes swap.
if (touch.id === touchStartId && distance(touchStart, touch.location > threshold) {
    scrollState = ScrollState.Scrolling;
    swapCssClasses();

    // If you have to manually scroll the div to prevent jump:
    $('.myContainer').scrollTop(containerTop + (touch.location.y - touchStart.y));
    // Do the same for horizontal scroll.
}

// Then, listen for debounced scroll events, like you're already doing,
// to reset your state back to default.

Друга ідея: замість зміни класів css у своєму обробнику прокрутки встановіть позицію прокрутки діва безпосередньо на вісь, яку ви хочете заблокувати. IE, якщо ви прокручуєте горизонтально, завжди встановлюйте значення scrollTop своїм початковим значенням. Це також може скасувати прокрутку, не впевнений. Вам доведеться спробувати, щоб побачити, чи працює він.


Я спробував це, але це було супер стрибковим, і виступ був жахливим.
Джош О'Коннор

3

Існує чимало способів вирішити це. Тут пропонується кілька хороших ідей.

Однак, як наголошували інші, покладатися на (або намагатися уникнути) багатовимірної прокрутки є поганим запахом UX - це свідчить про проблему UX. Я не думаю, що це законна проблема розробників. Було б краще зробити крок назад і переоцінити те, що ви намагаєтеся досягти. Одне з питань може полягати в тому, що, намагаючись зробити інтерфейс більш корисним, ви будете заплутати користувачів. Описана тут зручність використання, ймовірно, спричинить заплутаність.

Чому я не можу прокручувати горизонтально?

Чому, коли я перестаю прокручувати вертикально, тільки тоді я можу прокручувати горизонтально?

Ось деякі питання, які можуть бути задані (не чутні).

Якщо ви намагаєтеся дозволити додаткову інформацію списку вертикальних даних переглядати лише тоді, коли користувач обрав рядок, можливо, буде набагато краще просто мати плоский список за замовчуванням лише вертикально прокручуватись і лише перемикати вертикаль інформація, коли "рядок" вибрано / активовано. Згортання деталей поверне вас до плоского вертикального списку.

Якщо вам доведеться стрибати через обручі, щоб вирішити таку межу технічної проблеми, це хороший показник того, що досвід користувача не був спроектований для початку.


3

Потрібно використовувати три контейнери.
У першому контейнері я включаю вертикальну прокрутку та забороняю горизонтальну.
У другому, навпаки, я включаю горизонтальну прокрутку і забороняю вертикаль. Обов'язково використовувати overflow-x: hidden;і overflow-y: hidden;, в іншому випадку дитина контейнери можуть виходити за межі поточного контейнера.
Також потрібно використовувати min-width: 100%; min-height: 100%;.
Для третього контейнера нам потрібно використовувати, display: inline-block;і тоді внутрішній вміст розтягне цей контейнер, і відповідні смуги прокрутки з’являться на двох батьківських блоках.

HTML

<div class="scroll-y">
  <div class="scroll-x">
    <div class="content-container">

      <!-- scrollable content here -->

    </div>
  </div>
</div>

CSS

.scroll-y {
  position: absolute;
  overflow-x: hidden;
  overflow-y: auto;
  width: 100%;
  height: 100%;
  min-width: 100%;
  min-height: 100%;
}

.scroll-x {
  overflow-y: hidden;
  overflow-x: auto;
  width: auto;
  min-width: 100%;
  min-height: 100%;
}

.content-container {
  min-width: 100%;
  min-height: 100%;
  display: inline-block;
}

Ви можете протестувати його тут, у Safari на iPhone.

Удачі!! 😉


: підняті руки:: підняті руки:
cup_of

0

це виглядає як весело;)

Я не буду сперечатися, якщо це розумно.

Я спробував це з RxJS:

  ngAfterViewInit() {
    const table = document.getElementById("table");

    const touchstart$ = fromEvent(table, "touchstart");
    const touchmove$ = fromEvent(table, "touchmove");
    const touchend$ = fromEvent(table, "touchend");

    touchstart$
      .pipe(
        switchMapTo(
          touchmove$.pipe(
            // tap(console.log),
            map((e: TouchEvent) => ({
              x: e.touches[0].clientX,
              y: e.touches[0].clientY
            })),
            bufferCount(4),
            map(calculateDirection),
            tap(direction => this.setScrollingStyles(direction)),
            takeUntil(touchend$)
          )
        )
      )
      .subscribe();
  }

Ми буфер кожне 4 - е touchemoveподії , а потім зробити деякі досить складні обчислення з координатами чотирьох подій ( map(calculateDirection)) , яка виводить RIGHT, LEFT, UPабо DOWNі на підставу , що я намагаюся відключити вертикальну або horicontal прокрутки. На моєму андроїд-телефоні в хромі це працює;)

Я створив маленький ігровий майданчик , який можна було б покращити, переписати, що б там не було ...

Ура, Крис

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.