Beim vertikalen Scrollen kein horizontales Scrollen zulassen (und umgekehrt)


17

Ich habe eine Liste mit der overflow-xund overflow-ygesetzt auf auto. Außerdem habe ich Momentum Scroll eingerichtet, damit das Touch-Scrollen in Mobilgeräten mit funktioniert webkit-overflow-scrolling: true.

Das Problem ist jedoch, dass ich nicht herausfinden kann, wie der horizontale Bildlauf beim vertikalen Bildlauf deaktiviert werden kann. Dies führt zu einer sehr schlechten Benutzererfahrung, da durch Wischen nach oben links oder oben rechts die Tabelle diagonal gescrollt wird. Wenn der Benutzer vertikal scrollt, möchte ich auf keinen Fall horizontal scrollen, bis der Benutzer aufgehört hat, vertikal zu scrollen.

Ich habe folgendes versucht:

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

Aber jedes Mal , wenn ich einstelle overflow-xoder wenn es gescrollt wird, wird das Scrollen fehlerhaft und springt zurück nach oben. Ich habe auch bemerkt, dass dies der Grund ist, warum dies auftritt, wenn ich es entferne, scheint das Verhalten zu stoppen, aber ich brauche dies unbedingt für das Momentum-Scrollen in mobilen Geräten.overflow-yhiddenwebkit-overflow-scrolling: true

Wie deaktiviere ich den horizontalen Bildlauf beim vertikalen Bildlauf?


Ich weiß nicht, wie ich das Bildlaufproblem beheben soll. Vielleicht einen Schritt zurücktreten und versuchen, zu verhindern, dass eine der beiden Achsen trotzdem scrollt? Off-Topic: Tabellen sind nicht für wirklich kleine Bildschirme gedacht.
Joep Kockelkorn

In Ihrem Code fehlt eine geschweifte Klammer. Wenn Sie es als Snippet hinzufügen, wird in der Konsole eine Fehlermeldung angezeigt.
Razvan Zamfir

nur eine blöde Idee. Warum nicht zwei Schieberegler oder benutzerdefinierte Schieberegler zum Scrollen verwenden?
Thomas Ludewig

Antworten:


4

Versuche dies

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

Warum verwenden Sie nicht zwei, anstatt ein Div zum Scrollen zu verwenden? Habe eins für X und eins für Y.


1
Großartige Idee! Ich werde es versuchen.
Josh O'Connor

1
Lol, ich muss sagen, das ist eine geniale Idee.
frodo2975

15

Es ist im Allgemeinen eine schlechte Praxis für Ihr Design, ein mehrachsiges Scrollen auf Mobilgeräten zu benötigen, es sei denn, Sie zeigen möglicherweise große Datentabellen an. Warum wollen Sie das verhindern? Wenn ein Benutzer diagonal scrollen möchte, scheint mir das nicht das Ende der Welt zu sein. Einige Browser, wie Chrome unter OSX, tun bereits das, was Sie standardmäßig beschreiben.

Wenn Sie einen einachsigen Bildlauf benötigen, besteht eine mögliche Lösung darin, die Bildlaufposition selbst über touchstartund touchmoveEreignisse zu verfolgen . Wenn Sie Ihren Drag-Schwellenwert niedriger als den des Browsers einstellen, können Sie möglicherweise Ihre CSS-Aufgaben erledigen, bevor der Bildlauf beginnt, um den wahrgenommenen Fehler zu vermeiden. Auch wenn es immer noch Störungen gibt, haben Sie den Start der Berührung und den aktuellen Standort der Berührung. Wenn Sie die Start-Scroll-Position Ihres Divs aufzeichnen, können Sie das Div manuell an die richtige Stelle scrollen, um dem Springen nach oben entgegenzuwirken, wenn Sie müssen. Ein möglicher Algorithmus könnte folgendermaßen aussehen:

// 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.

Zweite Idee: Anstatt in Ihrem Bildlauf-Handler die CSS-Klassen zu ändern, legen Sie die Bildlaufposition des Div direkt für die Achse fest, die Sie sperren möchten. IE, wenn Sie horizontal scrollen, setzen Sie das scrollTop immer auf seinen Startwert. Dies kann auch das Scrollen abbrechen, nicht sicher. Sie müssten es versuchen, um zu sehen, ob es funktioniert.


Ich habe es versucht, aber es war super nervös und die Leistung war schrecklich.
Josh O'Connor

3

Es gibt zahlreiche Möglichkeiten, dies zu lösen. Hier werden einige gute Ideen angeboten.

Wie andere bereits angedeutet haben, ist es jedoch ein schlechter UX-Geruch, sich auf mehrdimensionales Scrollen zu verlassen (oder dies zu vermeiden) - ein Hinweis darauf, dass UX ein Problem darstellt. Ich denke nicht, dass dies ein legitimes Entwicklerproblem ist. Es wäre besser, einen Schritt zurückzutreten und neu zu bewerten, was Sie erreichen möchten. Eines der Probleme könnte sein, dass Sie Benutzer verwirren, um die Benutzeroberfläche benutzerfreundlicher zu gestalten. Die hier beschriebene Benutzerfreundlichkeit würde wahrscheinlich Verwirrung stiften.

Warum kann ich nicht horizontal scrollen?

Warum kann ich nur dann horizontal scrollen, wenn ich aufhöre, vertikal zu scrollen?

Dies sind einige Fragen, die möglicherweise gestellt werden (unhörbar).

Wenn Sie versuchen möchten, dass zusätzliche Informationen der vertikalen Datenliste nur durchsucht werden können, wenn der Benutzer die Zeile ausgewählt hat, ist es wahrscheinlich viel besser, einfach eine flache Liste zu haben, die standardmäßig nur vertikal scrollbar ist, und nur die vertikale umzuschalten Informationen, wenn die "Zeile" ausgewählt / aktiviert wurde. Wenn Sie die Details reduzieren, kehren Sie zur flachen vertikalen Liste zurück.

Wenn Sie durch Reifen springen müssen, um eine solche technische Randherausforderung zu lösen, ist dies ein guter Hinweis darauf, dass die Benutzererfahrung von Anfang an nicht gut gestaltet wurde.


3

Es müssen drei Behälter verwendet werden.
Im ersten Container aktiviere ich vertikales Scrollen und verbiete horizontales Scrollen.
Im zweiten Fall aktiviere ich das horizontale Scrollen und verbiete das vertikale Scrollen. Verwenden Sie unbedingt overflow-x: hidden;und overflow-y: hidden;, da sonst untergeordnete Container möglicherweise über den aktuellen Container hinausgehen.
Müssen auch verwenden min-width: 100%; min-height: 100%;.
Für den dritten Container müssen wir verwenden, display: inline-block;und dann wird der interne Inhalt diesen Container dehnen und die entsprechenden Bildlaufleisten werden auf den beiden übergeordneten Blöcken angezeigt.

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

Sie können es hier in Safari auf dem iPhone testen .

Viel Glück!! 😉


: erhobene Hände
::

0

das sieht nach spaß aus;)

Ich werde nicht darüber streiten, ob es vernünftig ist.

Ich habe es mit RxJS versucht:

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

Wir puffern jedes 4. touchemoveEreignis und führen dann eine hochentwickelte Berechnung mit den Koordinaten der vier Ereignisse ( map(calculateDirection)) durch, die ausgegeben RIGHTwerden LEFT, UPoder DOWNund basierend darauf versuche ich, das vertikale oder horizontale Scrollen zu deaktivieren. Auf meinem Android-Handy in Chrom funktioniert es irgendwie;)

Ich habe einen kleinen Spielplatz geschaffen , der verbessert, umgeschrieben, was auch immer ...

Prost Chris

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.