PrimeNG Table Sticky 的用法
- 先牢骚,官方给的代码用在
Angular8
和RxJS6
版本上有兼容的问题,主要是RxJS6
有很多breaking changes
,下面贴出来自己验证过成功的代码 - 2019年7月30日 13:15:31 -
制作指令:
import { Directive, Input, Renderer, ElementRef, AfterViewInit, OnDestroy, OnChanges } from '@angular/core'; import { Subscription,fromEvent } from 'rxjs'; @Directive({ selector: '[stickyHeader]' }) export class StickyHeaderDirective implements AfterViewInit, OnDestroy, OnChanges{ private windowScrollSubscription: Subscription = null; private windowResizeSubscription: Subscription = null; private header: any = null; private offsetTop: number = 0; private lastScroll: number = 0; private isSticky: boolean = false; private hasHeader: boolean = false; private headerTop = 0; @Input('stickyClass') stickyClass: string = ""; @Input('stickyTop') stickyTop: number = 0; constructor(private elementRef: ElementRef, private renderer: Renderer) { } ngAfterViewInit(): void { setTimeout(()=>{ this.windowScrollSubscription = fromEvent(window, 'scroll').subscribe(() => this.manageScrollEvent()); this.windowResizeSubscription = fromEvent(window, 'resize').subscribe(() => this.updateHeaderSize()); const headers = this.elementRef.nativeElement.getElementsByTagName('TR'); this.hasHeader = headers.length > 0; if (this.hasHeader) { this.header = headers[0]; this.headerTop = this.header.getBoundingClientRect()['top']; this._calcPosition(); } }, 0); } ngOnDestroy(): void { if (this.windowScrollSubscription){ this.windowScrollSubscription.unsubscribe(); this.windowScrollSubscription = null; } if (this.windowResizeSubscription){ this.windowResizeSubscription.unsubscribe(); this.windowResizeSubscription = null; } } ngOnChanges(changes) { if (changes.stickyTop) { this._calcPosition(); } } private _calcPosition(){ if (this.hasHeader) { const scroll = window.pageYOffset; if (this.isSticky && scroll >= this.headerTop) { this.header.style.top = this.stickyTop + 'px'; } } } private manageScrollEvent(): void { const scroll = window.pageYOffset; if (scroll > this.lastScroll && !this.isSticky && scroll >= this.offsetTop) { this.setSticky(); } else if (scroll < this.lastScroll && this.isSticky && scroll <= this.offsetTop) { this.unsetSticky(); } this.lastScroll = scroll; } private setSticky(): void { this.isSticky = true; this.header.style.position = 'fixed'; this.header.style.top = this.stickyTop + 'px'; this.header.style.display = 'table'; this.updateHeaderSize(); this.setClass(true); } private updateHeaderSize(){ if (this.isSticky) { const tableWidth = this.elementRef.nativeElement.getBoundingClientRect()['right'] - this.elementRef.nativeElement.getBoundingClientRect()['left']; this.header.style.width = tableWidth + 'px'; // update size of TH elements const thArray = this.elementRef.nativeElement.getElementsByTagName('TH'); for (let i = 0; i < thArray.length; i++){ thArray[i].style.width = tableWidth / thArray.length + "px"; } } } private unsetSticky(): void { this.isSticky = false; this.header.style.position = 'static'; this.header.style.width = 'auto'; this.header.style.display = 'table-row'; this.setClass(false); } private setStyle(key: string, value: string): void { this.renderer.setElementStyle(this.header, key, value); } private setClass(add: boolean): void { if (this.stickyClass){ this.renderer.setElementClass(this.header, this.stickyClass, add); } } }
- 将制作的指令导入组件所在模块
- 模板中使用
sticky
指令:
上面被注释的属性 [stickyTop]=50
可以指定下拉时列头举例屏幕上面的举例
-
设置
css
样式:.header{ height: 50px; width: 100%; background-color:cornflowerblue; color: white; font-size: 16px; font-weight: bold; font-family: Arial; line-height: 50px; text-align: center; border-bottom: 1px solid #666666; position: fixed; z-index: 1; top: 0px; } p-dataTable{ margin-left: 20px; margin-top: 50px; margin-right: 20px; display: block; } :host /deep/ p-datatable .stickyHeader{ box-shadow: 2px 2px 1px #888888; }
- 最终效果
- 纠正官方代码的不兼容问题:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。