如何在 Angular 8 的 primeng 选项卡视图中为左右导航添加箭头?

How to add arrows for left and right navigations in primeng tab view in Angular 8?

我希望添加左右导航箭头以支持导航中更大的标签尺寸。

我尝试使用 primeng,因为我的应用程序已经有了这个带有 Angular 8.

的库

除了 Angular Material 之外,还有其他库支持此功能吗?

我在这里创建了示例。

https://stackblitz.com/edit/primeng-tabview-ngif-hluezs

Angular material 示例。

https://stackblitz.com/edit/angular-selecting-mattab-bihcd1

我分叉了您的示例,并在顶部添加了一些示例按钮,可以转到 previous/next 选项卡。当然,您可以通过几种不同的方式执行此操作。

https://stackblitz.com/edit/primeng-tabview-ngif-2e96sb?file=src/app/app.component.html

让我知道 CSS 是否是问题所在,因为这主要是为了展示功能。

您可以创建自己的指令来实现此...

在您的 styles.css 文件中包含以下 css

.nav-wrapper {
  position: relative;
  overflow: hidden;
  padding: 0;
}
.nav-wrapper > ul {
  display: flex;
}

.nav-wrapper--scrollable {
  padding: 0 32px;
}

.nav-arrow {
  position: absolute;
  display: none;
  top: 0;
  bottom: 0;
  z-index: 1;
  border: 1px solid #2399e5;
  background: #2399e5;
  font: 14px/1 FontAwesome;
  color: #fff;
  cursor: pointer;
}
.nav-wrapper--scrollable .nav-arrow {
  display: block;
}
.nav-arrow:hover {
  border: 1px solid #1f89ce;
  background: #1f89ce;
}

.nav-arrow:before {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.nav-arrow--left {
  left: 0;
}
.nav-arrow--left:before {
  content: "\f053";
}

.nav-arrow--right {
  right: 0;
}
.nav-arrow--right:before {
  content: "\f054";
}
.nav-arrow--disabled,
.nav-arrow--disabled:hover {
  background: #ccc;
  border: #ddd;
  cursor: default;
}

创建指令

import {
  ContentChildren,
  Directive,
  ElementRef,
  Input,
  NgZone,
  QueryList
} from "@angular/core";
import { TabPanel } from "primeng/tabview";
import { fromEvent, interval, Subject } from "rxjs";
import { delay, mergeMap, take, takeUntil } from "rxjs/operators";

@Directive({
  selector: "[appTabScroller]"
})
export class TabScrollerDirective {
  @Input() arrowWidth = 30;
  @Input() shiftWidth = 25;

  @ContentChildren(TabPanel) tabPanels: QueryList<TabPanel>;

  private _container: HTMLElement;
  private _nav: HTMLElement;

  private _shift = 0;
  private _scrollable: boolean;

  private _leftArrow: HTMLElement;
  private _rightArrow: HTMLElement;

  private readonly _destroyed$ = new Subject<void>();

  constructor(private elRef: ElementRef, private zone: NgZone) {}

  get rightBorder() {
    return -(this._nav.scrollWidth - this._nav.offsetWidth);
  }

  ngAfterContentInit() {
    this.tabPanels.changes.pipe(takeUntil(this._destroyed$)).subscribe(() => {
      this.zone.onStable
        .asObservable()
        .pipe(take(1))
        .subscribe(() => this._refreshScroller());
    });
  }

  ngAfterViewInit() {
    this.zone.runOutsideAngular(() => this.init());
  }

  init() {
    this._nav = this.elRef.nativeElement.querySelector("[role=tablist]");
    this._container = wrap(this._nav, "nav-wrapper");

    this._initEvents();

    this._leftArrow = this._createArrow("left");
    this._rightArrow = this._createArrow("right");

    this._refreshScroller();
  }

  scroll(shift: number) {
    this._shift += shift;

    const rightBorder = this.rightBorder;
    if (this._shift < rightBorder) {
      this._shift = rightBorder;
    }
    if (this._shift >= 0) {
      this._shift = 0;
    }

    this._leftArrow.classList.toggle("nav-arrow--disabled", this._shift >= 0);
    this._rightArrow.classList.toggle(
      "nav-arrow--disabled",
      this._shift <= rightBorder
    );

    this._nav.style.transform = `translateX(${this._shift}px)`;
  }

  ngOnDestroy() {
    this._destroyed$.next();
    this._destroyed$.complete();
  }

  private _initEvents() {
    fromEvent(this._container, "mousewheel")
      .pipe(takeUntil(this._destroyed$))
      .subscribe((e: any) => this._onMouseWheel(e));
    // Firefox
    fromEvent(this._container, "DOMMouseScroll")
      .pipe(takeUntil(this._destroyed$))
      .subscribe((e: any) => this._onMouseWheel(e));
    fromEvent(window, "resize")
      .pipe(takeUntil(this._destroyed$))
      .subscribe(() => {
        this._refreshScroller();
      });
  }

  private _onMouseWheel(e: any) {
    const delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.detail));
    this.scroll(delta * 25);
  }

  private _createArrow(direction: string) {
    const arrow = el(`nav-arrow nav-arrow--${direction}`);
    this._container.insertBefore(arrow, this._nav);
    arrow.style.width = this.arrowWidth + "px";
    fromEvent(arrow, "click")
      .pipe(takeUntil(this._destroyed$))
      .subscribe(() => {
        this.scroll(direction === "left" ? this.shiftWidth : -this.shiftWidth);
      });

    const upStream$ = fromEvent(arrow, "mouseup");
    // handle long press
    fromEvent(arrow, "mousedown")
      .pipe(
        takeUntil(this._destroyed$),
        mergeMap(event =>
          interval(100).pipe(
            delay(100),
            takeUntil(upStream$)
          )
        )
      )
      .subscribe(() => {
        this.scroll(direction === "left" ? this.shiftWidth : -this.shiftWidth);
      });

    return arrow;
  }

  private _refreshScroller() {
    const compareWith = this._scrollable ? -this.arrowWidth * 2 : 0;
    this._container.classList.toggle(
      "nav-wrapper--scrollable",
      this.rightBorder < compareWith
    );
    this._scrollable = this.rightBorder < compareWith;
    this.scroll(0);
  }
}

function wrap(elem, wrapperClass: string) {
  const wrapper = el("nav-wrapper");
  elem.parentNode.insertBefore(wrapper, elem);
  wrapper.appendChild(elem);
  return wrapper;
}

function el(className: string): HTMLElement {
  const div = document.createElement("div");
  div.className = className;
  return div;
}

现在一切就绪,在您的 html

<p-tabView appTabScroller>
  <p-tabPanel [header]="item.content" *ngFor="let item of items; let i = index" [selected]="i == 0">
  </p-tabPanel>
</p-tabView>

See Demo

来源:https://embed.plnkr.co/BX6UTrG7XTBXS2TNChAs/