簡體   English   中英

使材料選項卡可滾動

[英]Making Material tabs scrollable

我在我的應用程序中使用了材料選項卡( mat-tab mat-tab-group )當有更多的標簽時比可以顯示更多的標簽,兩個導航按鈕顯示為顯示其他選項卡:

在此處輸入圖片說明

我的要求是讓用戶能夠在選項卡欄上滾動,以便顯示其他選項卡。

我試圖做一些 css 更改,但無法解決。 如果可以提供任何解決方案或建議,我們將不勝感激。

[長文本解決方案] 我的目標是默認情況下使 mat-tabs 可滾動,無需控件,但能夠在單擊部分可見的 mat-tab 以將其移動到可見的中心視口時自動滾動。

1)此行為已在此示例“開箱即用”中部分實現 - https://stackblitz.com/edit/angular-mat-tabs-scrollalble-initial-behavior 問題是你不能正常向后滾動 - 有一些錯誤的行為將標簽推到左邊。 所以它不能像我想要的那樣工作。

2)下一個變體是滾動事件 - 在 mat-tab-group 上使用(wheel)="event" - 但它也不適用於移動設備。 https://stackblitz.com/edit/angular-mat-tabs-scrollable-by-wheel-event上面這個很棒的評論中得到了它。

3) 我自己的 mat-tabs 滾動,當您單擊選項卡時,在移動設備上滾動並自動將單擊的選項卡滾動到屏幕的視口中心並不太簡單,但它確實有效! :)

首先,您需要在點擊選項卡和分頁按鈕時禁用“從框中”滾動:

mat-tabs-override.scss:

$black: #121212;
@mixin media-query-for-mobile {
  @media (max-width: 768px) and (min-width: 1px) {
    @content;
  }
}
mat-tab-group {
  .mat-tab-header {
    .mat-tab-header-pagination {
      display: none !important; // <== disable pagination
    }
    .mat-tab-label-container {
      left: 0px; // if you need to use it on mobile - set left position to 0
      width: 100%;
      .mat-tab-list {
        overflow-x: auto !important; // <== set horisontal scroll bar imperatively
        // below rule prevents sliding of buttons' container - because it not sliding properly - to left it not slide as well
        transform: none !important;
        .mat-tab-labels {
          // some tweaks for tabs - up to you
          @include media-query-for-mobile {
            justify-content: unset !important; 
          }
          .mat-tab-label {
            // min-width: 20% !important;
            padding: 1.25% !important;
            margin: 0px !important;
            text-transform: uppercase;
            color: $black;
            font-weight: 600;
            min-width: 140px !important;
          }
        }
      }
    }
  }
}

在這種情況下,您會看到所有選項卡的寬度都相似,並且可以在移動設備上滾動。

接下來,您需要在單擊選項卡時自動滾動選項卡並根據當前視口將它們的位置更改為屏幕中心 - 讓我們來做吧!

我們可以創建一個指令,它將監聽<mat-tabs-group>的主容器,檢查可滾動容器的寬度.mat-tab-labels並通過自動滾動.mat-tabs-labels移動選項卡以在視口中可見.mat-tabs-labels容器.mat-tabs-labels為所需的方式:

模板中的指令:

<mat-tab-group scrollToCenter>
    <mat-tab label="tab 1"></mat-tab>
    <mat-tab label="tab 2"></mat-tab>
    <mat-tab label="tab 3"></mat-tab>
    <mat-tab label="tab 4"></mat-tab>
    <mat-tab label="tab 5"></mat-tab>
    <mat-tab label="tab 6"></mat-tab>
    <mat-tab label="tab 7"></mat-tab>
    <mat-tab label="tab 8"></mat-tab>
</mat-tab-group>

指令.ts:

import { Directive, ElementRef, OnDestroy } from '@angular/core';
import { fromEvent, Subscription } from 'rxjs';

interface DOMRectI {
  bottom: number;
  height: number;
  left: number; // position start of element
  right: number; // position end of element
  top: number;
  width: number; // width of element
  x?: number;
  y?: number;
}

@Directive({
  // tslint:disable-next-line:directive-selector
  selector: '[scrollToCenter]',
})
export class MatTabScrollToCenterDirective implements OnDestroy {
  isMobile: boolean;
  subs = new Subscription();
  constructor(
    private element: ElementRef
  ) {
    this.subs.add(
      fromEvent(this.element.nativeElement, 'click').subscribe((clickedContainer: MouseEvent) => {
        const scrollContainer = this.element.nativeElement.querySelector('.mat-tab-list');
        const currentScrolledContainerPosition: number = scrollContainer.scrollLeft;

        const newPositionScrollTo = this.calcScrollToCenterValue(clickedContainer, currentScrolledContainerPosition);
      })
    );
  }

/** calculate scroll position to center of viewport */
  calcScrollToCenterValue(clickedContainer, currentScrolledContainerPosition): number {
    const scrolledButton: DOMRectI = (clickedContainer.target as HTMLElement).getBoundingClientRect();
    const leftXOffset = (window.innerWidth - scrolledButton.width) / 2;
    const currentVisibleViewportLeft = scrolledButton.left;
    const neededLeftOffset = currentVisibleViewportLeft - leftXOffset;
    console.log(scrolledButton);
    const newValueToSCroll = currentScrolledContainerPosition + neededLeftOffset;
    return newValueToSCroll;
  }

  ngOnDestroy() {
    this.subs.unsubscribe();
  }
}


它有效! :0 但不是在 ios 和 IE ... 為什么? 因為ios和IE不支持Element.scroll()

解決方案 - npm i element-scroll-polyfill並設置為 polyfills.ts

/** enable polufill for element.scroll() on IE and ios */
import 'element-scroll-polyfill';

偉大的! 但現在滾動不是那么流暢... IE 和 ios 不支持平滑滾動行為。

解決方案 - npm i smoothscroll-polyfill並添加到npm i smoothscroll-polyfill

import smoothscroll from 'smoothscroll-polyfill';
// enable polyfill
smoothscroll.polyfill();

最后它無處不在。 希望它可以幫助某人修復 mat-tabs 自動滾動空虛:)

演示享受吧:)

在此stackblitz 演示中嘗試我的解決方案。

首先獲取對 matTabGroup 的引用:

應用程序組件.html

<mat-tab-group #tabGroup>
               ^^^^^^^^^  

app.component.ts

@ViewChild('tabGroup')
tabGroup;

然后監聽鼠標滾輪事件並觸發自定義滾動功能:

應用程序組件.html

<mat-tab-group (wheel)="scrollTabs($event)" #tabGroup>
                        ^^^^^^^^^^^^^^^^^^  

app.component.ts

scrollTabs(event) {
  const children = this.tabGroup._tabHeader._elementRef.nativeElement.children;

  // get the tabGroup pagination buttons
  const back = children[0];
  const forward = children[2];

  // depending on scroll direction click forward or back
  if (event.deltaY > 0) {
    forward.click();
  } else {
    back.click();
  }
}

免責聲明:此解決方案非常脆弱。 Angular Material 選項卡不提供用於執行此操作的 API。 解決方案取決於可能會在不通知的情況下更改的內部引用(例如這個私有變量this.tabGroup._tabHeader )。 此外,它還不會阻止頁面滾動,並且僅適用於垂直滾動。 (不過這兩個可以解決。)

試試這個純 css 解決方案StackBlitz

將此代碼放在使用 mat-tab 的同一組件中

 ::ng-deep .mat-tab-header { overflow-x: scroll !important; } ::ng-deep .mat-tab-label-container { overflow: visible !important; } ::ng-deep .mat-tab-header::-webkit-scrollbar { // TO Remove horizontal scrollbar in tabs display: none; }

在鼠標滾輪事件(上面發布)的頂部添加拖動事件和拖動開始事件以滾動 mat-tab-group 下的 strd mat-tab

 onDrag(event) { if (event.clientX > 0) { let deltaX = this.previousX - event.clientX; const children = this.tabGroup._tabHeader._elementRef.nativeElement.children; // get the tabGroup pagination buttons const back = children[0]; const forward = children[2]; console.log('dragging' + deltaX); // depending on scroll direction click forward or back if (deltaX > 3) { forward.click(); } else if (deltaX < -3) { back.click(); } } this.previousX = event.clientX; event.target.style.opacity = 1; } onDragStart(event) { this.previousX = event.clientX; event.target.style.opacity = 0; }
 .noselect { user-select: none; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */ }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script> <mat-card fxflex class="card component-right" *ngIf="editMode"> <mat-card-content class="card-content"> <mat-tab-group class="noselect" draggable="true" (drag)="onDrag($event)" (dragstart)="onDragStart($event)" (wheel)="scrollTabs($event)" #tabGroup> <mat-tab label="1st tab"> </mat-tab> <mat-tab label="2nd tab"> </mat-tab> <mat-tab label="3rd tab"> </mat-tab> <mat-tab label="4th tab"> </mat-tab> <mat-tab label="5th tab"> </mat-tab> <mat-tab label="6th tab"> </mat-tab> </mat-tab-group> </mat-card-content> </mat-card>

在此處輸入圖片說明

我們可以通過添加以下 css 代碼使 mat 標簽可滾動

 .mat-tab-labels
 {
 display : inline-flex !important;
 } 
 .mat-tab-label 
{
display:inline-table !important;
padding-top:10px !important;    
min-width:0px !important;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM