垂直滚动时不允许水平滚动(反之亦然)


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

但每次我一组overflow-xoverflow-yhidden当其被滚动,滚动将毛刺和跳回到顶部。我还注意到这webkit-overflow-scrolling: true是发生这种情况的原因,当我将其删除时,该行为似乎停止了,但是我绝对需要这样做才能在移动设备中进行动量滚动。

垂直滚动时如何禁用水平滚动?


我不知道如何解决滚动问题。也许退后一步,尝试阻止两个轴之一滚动?题外话:表格并不适合很小的屏幕。
Joep Kockelkorn

您的代码中缺少大括号。如果将其添加为摘要,则在控制台中将看到错误消息。
拉兹万·赞菲尔

只是一个愚蠢的想法。为什么不使用两个滑块或自定义滑块滚动?
Thomas Ludewig

Answers:


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

而不是使用一个div滚动,为什么不使用两个呢?X有一个,Y有一个


1
好点子!请给我一个机会。
乔什·奥康纳

1
大声笑,我不得不说这是一个巧妙的想法。
frodo2975

15

通常,在设计中需要在移动设备上进行多轴滚动是一种不好的做法,除非您正在显示大型数据表。话虽这么说,为什么要预防呢?如果用户想对角滚动,那对我来说似乎不是世界末日。默认情况下,某些浏览器(例如OSX上的Chrome)已经执行了您要描述的内容。

如果必须进行单轴滚动,则可能的解决方案可能是通过touchstarttouchmove事件自己跟踪滚动位置。如果将拖动阈值设置为低于浏览器的阈值,则可以在开始滚动之前进行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类,而是直接为要锁定的轴设置div的滚动位置。IE,如果要水平滚动,请始终将scrollTop设置为其初始值。不确定,这也可能会取消滚动。您必须尝试一下它是否有效。


我试过了,但是跳得很厉害,表现很糟糕。
乔什·奥康纳

3

有很多方法可以解决此问题。这里提供了一些好主意。

但是,正如其他人所暗示的那样,依靠(或尝试避免)多维滚动是一种不良的UX气味-表示UX是一个问题。我认为这不是合法的开发问题。最好退后一步,重新评估您要完成的工作。问题之一可能是,为了使UI更加可用,您将使用户感到困惑。这里描述的可用性可能会引起混乱。

为什么我不能水平滚动?

为什么当我停止垂直滚动时,才可以水平滚动?

这些是可能会被问到的(听不清)的问题。

如果您试图仅在用户选择行时才允许浏览垂直数据列表的其他信息,则默认情况下,仅具有一个垂直列表只能滚动,并且仅切换垂直选择/激活“行”时的信息。折叠细节会使您回到平面垂直列表。

如果您必须跳过障碍来解决此类附带的技术难题,则可以很好地表明,用户体验一开始就设计得不好。


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

您可以在iPhone的Safari中在此处进行测试。

祝好运!!😉


:举手::举手:
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),其输出)RIGHTLEFTUPDOWN基于我尝试禁用垂直或horicontal滚动。在我的Chrome安卓手机上,它可以工作;)

我已经创建了一个小操场,可以对其进行任何改进,重写...

干杯克里斯

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.