[英]Making Material tabs scrollable
[長文本解決方案] 我的目標是默認情況下使 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 演示中嘗試我的解決方案。
<mat-tab-group #tabGroup>
^^^^^^^^^
@ViewChild('tabGroup')
tabGroup;
<mat-tab-group (wheel)="scrollTabs($event)" #tabGroup>
^^^^^^^^^^^^^^^^^^
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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.