ไม่อนุญาตให้เลื่อนแนวนอนเมื่อเลื่อนแนวตั้ง (และกลับกัน)


17

ผมมีรายการที่มีoverflow-xและกำหนดให้overflow-y นอกจากนี้ผมได้ตั้งค่าเลื่อนโมเมนตัมเพื่อเลื่อนสัมผัสการทำงานมีความสุขในมือถือใช้autowebkit-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-xหรือoverflow-yไปhiddenเมื่อมันได้รับการเลื่อนเลื่อนจะ glitch และกระโดดกลับไปด้านบน ฉันยังสังเกตเห็นด้วยว่าwebkit-overflow-scrolling: trueนี่คือเหตุผลที่สิ่งนี้เกิดขึ้นเมื่อฉันลบออกพฤติกรรมดูเหมือนจะหยุดทำงาน แต่ฉันต้องการสิ่งนี้เพื่อเลื่อนโมเมนตัมในอุปกรณ์มือถือ

ฉันจะปิดการใช้งานการเลื่อนแนวนอนเมื่อเลื่อนในแนวตั้งได้อย่างไร


ฉันไม่ทราบวิธีแก้ไขปัญหาการเลื่อน อาจย้อนกลับไปหนึ่งก้าวและพยายามป้องกันหนึ่งในสองแกนจากการเลื่อน นอกหัวข้อ: ตารางไม่ได้มีไว้สำหรับหน้าจอขนาดเล็กจริงๆ
Joep Kockelkorn

ไม่มีเครื่องหมายวงเล็บปีกกาในรหัสของคุณ หากคุณเพิ่มเป็นข้อมูลโค้ดคุณจะเห็นข้อความแสดงข้อผิดพลาดในคอนโซล
Razvan Zamfir

แค่ความคิดที่โง่ ทำไมไม่ใช้สองเลื่อนหรือเลื่อนที่กำหนดเองเพื่อเลื่อน?
โทมัส Ludewig

แนวคิดที่เกี่ยวข้อง: stackoverflow.com/questions/24594653/…
James Dunn

คำตอบ:


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
ความคิดที่ดี! ไม่ให้กระสุนนี่
Josh O'Connor

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 ให้กำหนดตำแหน่งการเลื่อนของ div โดยตรงสำหรับแกนที่คุณต้องการล็อค IE หากคุณเลื่อนแนวนอนให้ตั้ง scrollTop เป็นค่าเริ่มต้นเสมอ นี่อาจยกเลิกการเลื่อนไม่แน่ใจ คุณต้องลองดูว่ามันใช้ได้หรือไม่


ฉันลองสิ่งนี้ แต่มันสุดยอดมากและการแสดงก็แย่มาก
Josh O'Connor

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

คุณสามารถทดสอบได้ที่นี่ใน 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();
  }

เรา buffer ทุก 4 touchemoveเหตุการณ์และจากนั้นทำให้การคำนวณมีความซับซ้อนสูงบางคนที่มีพิกัดในสี่ของเหตุการณ์ที่เกิดขึ้น ( map(calculateDirection)) ซึ่งผลRIGHT, LEFT, UPหรือDOWNและขึ้นอยู่กับว่าผมพยายามที่จะปิดการใช้งานการเลื่อนแนวตั้งหรือ horicontal บนโทรศัพท์ Android ของฉันในโครเมี่ยมมันทำงานได้;)

ฉันได้สร้างสนามเด็กเล่นเล็ก ๆซึ่งสามารถปรับปรุงเขียนใหม่ไม่ว่า ...

ไชโยคริส

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.