Không cho phép cuộn ngang khi cuộn theo chiều dọc (và ngược lại)


17

Tôi có một danh sách, với overflow-xoverflow-yđược đặt thành auto. Ngoài ra, tôi đã thiết lập cuộn đà, do đó, cuộn cảm ứng hoạt động tốt trên thiết bị di động, sử dụng webkit-overflow-scrolling: true.

Tuy nhiên, vấn đề là tôi không thể tìm ra cách vô hiệu hóa cuộn ngang khi cuộn theo chiều dọc. Nó dẫn đến trải nghiệm người dùng thực sự tồi tệ, vì việc vuốt về phía trên bên trái hoặc trên cùng bên phải sẽ khiến bảng cuộn theo đường chéo. Khi người dùng cuộn theo chiều dọc, tôi hoàn toàn KHÔNG muốn cuộn theo chiều ngang cho đến khi người dùng ngừng cuộn theo chiều dọc.

Tôi đã thử như sau:

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

Nhưng mỗi khi tôi đặt overflow-xhoặc overflow-yđến hiddenkhi nó được cuộn, cuộn sẽ bị trục trặc và nhảy trở lại đầu trang. Tôi cũng nhận thấy đó webkit-overflow-scrolling: truelà lý do tại sao điều này xảy ra, khi tôi gỡ bỏ nó, hành vi dường như dừng lại, nhưng tôi hoàn toàn cần điều này để cuộn đà trong thiết bị di động.

Làm cách nào để tắt cuộn ngang khi cuộn theo chiều dọc?


Tôi không biết cách khắc phục sự cố cuộn. Có thể lùi một bước và cố gắng ngăn một trong hai trục di chuyển không? Off-topic: Bàn không dành cho màn hình thực sự nhỏ.
Joep Kockelkorn

Có một dấu ngoặc nhọn bị thiếu trong mã của bạn. Nếu bạn thêm nó dưới dạng đoạn mã, bạn sẽ thấy thông báo lỗi trong bảng điều khiển.
Razvan Zamfir

chỉ là một ý tưởng ngu ngốc. Tại sao không sử dụng hai thanh trượt hoặc thanh trượt tùy chỉnh để cuộn?
Thomas Ludewig

Câu trả lời:


4

Thử cái này

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

Thay vì sử dụng một div để cuộn, tại sao bạn không sử dụng hai div? Có một cho X và một cho Y


1
Ý tưởng tuyệt vời! Tôi cho điều này một shot.
Josh O'Connor

1
Lol, tôi phải nói rằng đây là một ý tưởng khéo léo.
frodo2975

15

Nói chung, đó là một thực tế tồi cho thiết kế của bạn cần cuộn nhiều trục trên thiết bị di động, trừ khi có thể bạn đang hiển thị các bảng dữ liệu lớn. Điều đó đang được nói, tại sao bạn muốn ngăn chặn nó? Nếu người dùng muốn cuộn theo đường chéo, đó dường như không phải là ngày tận thế đối với tôi. Một số trình duyệt, như Chrome trên OSX, đã thực hiện những gì bạn mô tả theo mặc định.

Nếu bạn phải có đơn trục di chuyển, một giải pháp khả thi có thể là để theo dõi các vị trí cuộn mình qua touchstarttouchmovesự kiện. Nếu bạn đặt ngưỡng kéo thấp hơn trình duyệt, bạn có thể thực hiện công cụ css của mình trước khi bắt đầu cuộn, tránh trục trặc nhận thức. Ngoài ra, ngay cả khi nó vẫn không ổn, bạn vẫn có cảm ứng bắt đầu và vị trí hiện tại của cảm ứng. Từ những điều này, nếu bạn ghi lại vị trí cuộn bắt đầu của div, bạn có thể cuộn div theo cách thủ công đến đúng vị trí để chống lại nó nhảy lên trên cùng nếu bạn phải. Một thuật toán có thể có thể trông như thế này:

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

Ý tưởng thứ hai: trong trình xử lý cuộn của bạn, thay vì thay đổi các lớp css, hãy đặt vị trí cuộn của div trực tiếp cho trục bạn muốn khóa. IE, nếu bạn đang cuộn theo chiều ngang, luôn đặt scrollTop thành giá trị bắt đầu của nó. Điều này cũng có thể hủy cuộn, không chắc chắn. Bạn sẽ phải thử nó để xem nó hoạt động.


Tôi đã thử điều này nhưng nó siêu nhảy và hiệu suất là khủng khiếp.
Josh O'Connor

3

Có rất nhiều cách để cố gắng giải quyết điều này. Một số ý tưởng tốt được cung cấp ở đây.

Tuy nhiên, như những người khác đã ám chỉ, dựa vào (hoặc cố gắng tránh) cuộn đa chiều là một mùi UX xấu - cho thấy UX là một vấn đề. Tôi không nghĩ rằng đây là một vấn đề dev hợp pháp. Sẽ tốt hơn nếu lùi lại một bước và đánh giá lại những gì bạn đang cố gắng thực hiện. Một trong những vấn đề có thể là trong nỗ lực làm cho UI dễ sử dụng hơn, bạn sẽ khiến người dùng bối rối. Khả năng sử dụng được mô tả ở đây có thể sẽ gây nhầm lẫn.

Tại sao tôi không thể cuộn theo chiều ngang?

Tại sao khi tôi ngừng cuộn theo chiều dọc, chỉ sau đó tôi mới có thể cuộn theo chiều ngang?

Đây là một số câu hỏi có thể được hỏi (không nghe được).

Nếu bạn đang cố gắng cho phép thông tin bổ sung của danh sách dữ liệu dọc chỉ có thể duyệt được khi người dùng đã chọn hàng, thì có thể tốt hơn là chỉ có một danh sách phẳng theo mặc định chỉ có thể cuộn theo chiều dọc và chỉ chuyển đổi theo chiều dọc thông tin khi "hàng" đã được chọn / kích hoạt. Thu gọn các chi tiết sẽ đưa bạn trở lại danh sách dọc phẳng.

Nếu bạn phải vượt qua các vòng để giải quyết một thách thức kỹ thuật bên lề như vậy, thì đó là một dấu hiệu tốt cho thấy trải nghiệm người dùng không được thiết kế tốt để bắt đầu.


3

Cần sử dụng ba container.
Trong thùng chứa đầu tiên tôi cho phép cuộn dọc và không cho phép ngang.
Trong lần thứ hai, ngược lại, tôi cho phép cuộn ngang và không cho phép dọc. Hãy chắc chắn để sử dụng overflow-x: hidden;overflow-y: hidden;, nếu không, container trẻ em có thể vượt ra ngoài container hiện tại.
Cũng cần sử dụng min-width: 100%; min-height: 100%;.
Đối với vùng chứa thứ ba, chúng ta cần sử dụng display: inline-block;và sau đó nội dung bên trong sẽ kéo dài vùng chứa này và các thanh cuộn tương ứng sẽ xuất hiện trên hai khối chính.

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

Bạn có thể kiểm tra nó ở đây trong Safari trên iPhone.

Chúc may mắn!! 😉


: giơ tay:: tay giơ lên:
cup_of

0

điều này có vẻ vui

Tôi sẽ không tranh luận về việc nếu nó hợp lý.

Tôi đã thử nó với 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();
  }

Chúng tôi đệm mỗi thứ 4 touchemovesự kiện và sau đó thực hiện một số tính toán rất tinh vi với các tọa độ trong bốn sự kiện ( map(calculateDirection)) mà kết quả đầu ra RIGHT, LEFT, UPhay DOWNvà trên cơ sở đó tôi cố gắng vô hiệu hóa di chuyển theo chiều dọc hoặc horicontal. Trên điện thoại Android của tôi bằng chrome, nó hoạt động tốt;)

Tôi đã tạo ra một sân chơi nhỏ , có thể được tăng cường, viết lại, bất cứ điều gì ...

Chúc mừng Chris

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.