如何正确地为表头设置粘性样式?

8

我在数据表格中的固定表头样式方面遇到了一些小问题。我编写了一个简单的Angular组件和特定的指令:

sticky.directive.ts

@Directive({
    selector: '[sticky]'
})
export class StickyDirective {

    constructor(private _element: ElementRef, private _window: WindowRef) {
        console.log('debug')
    }

    @HostListener('window:scroll', ['$event'])
    handleScrollEvent(e) {
        if (this._window.nativeWindow.pageYOffset > 100) {
            this._element.nativeElement.classList.add('stick');
        } else {
            this._element.nativeElement.classList.remove('stick');
        }
    }
}

该指令的目的是在用户滚动到标题下方时添加一个类 stick。因此,即使用户滚动了长表格,表头也应对用户可见。stick 类看起来像这样:
.stick {
    position: fixed;
    top: 55px;
} 

以下是我的some.component.html的部分内容(在thead元素上使用指令):

<table class=" table table-bordered ">
 <thead sticky>
   <tr>
    <th width="40%">Name
    </th>
    <th width="10%">Priority
    </th>
    <th width="25%">Date created
    </th>
    <th width="25%">Date modified
    </th>   </tr>   </thead>   <tbody>   <tr *ngFor="let r of entitiesFiltered">
    <td>
      <div class="table-cell-flex">
        <div class="cell-content">
          {{r.name}}
        </div>
      </div>
    </td>
    <td>
      <div class="table-cell-flex">
        <div class="cell-content">
          {{r.priority}}
        </div>
      </div>
    </td>
...

我的代码实现了基本功能。这意味着当页面滚动时,标题仍保持在原位,但标题和列的宽度会发生变化。效果如下:enter image description here


问题:

有人能告诉我该如何设置表格样式,使得固定的标题不会改变表格的形状吗?是否可能实现?


你需要给它一个与“容器”大小匹配的width和/或leftright值。你能否为我们提供链接或重新创建该页面,或告诉我主表格如何居中? - Michael Coker
2
当您的标题设置为position:fixed时,它会将元素从HTML流中移出,因此...它不再与表格相关联。把它看作你的thead现在是一个不同的表格,与你的tbody分开...所以给tbody和thead设置相同的宽度,并且不仅要为th而且也要为td设置宽度。 - Alvaro Menéndez
4个回答

0

我也遇到了同样的问题。
为了解决它,我创建了一个简单的hack,在粘性标题中设置了列的固定宽度,并在表格下面复制了粘性标题(以保留列名内容的宽度)。

我的解决方法基于Bootstrap 4Angular 6


example.component.html:

<table class="table">
  <thead>
  <tr>
    <th #tableColumn1>Column 1</th>
    <th #tableColumn2>Column 2</th>
    <th #tableColumn3>Column 3</th>
  </tr>
  </thead>
  <tbody>
  <tr *ngFor="let message of messages">
    <td>{{ message.title }}</td>
    <td>{{ message.author }}</td>
    <td>{{ message.created_at }}</td>
  </tr>
  </tbody>
</table>

<table class="table" [class.d-none]="!showFixedTableHeader">
  <thead>
  <tr [class.sticky]="showFixedTableHeader">
    <th [width]="tableColumn1.offsetWidth">Column 1</th>
    <th [width]="tableColumn2.offsetWidth">Column 2</th>
    <th [width]="tableColumn3.offsetWidth">Column 3</th>
  </tr>
  </thead>
</table>


example.component.ts

import {Component, HostListener} from '@angular/core';

@Component({
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent {

  showFixedTableHeader: boolean = false;

  @HostListener('window:scroll')
  onScroll() {
    const pageTopOffset = window.pageYOffset;

    if (pageTopOffset > 285) {
      this.showFixedTableHeader = true;
    } else {
      this.showFixedTableHeader = false;
    }
  }

  @HostListener('window:resize')
  onResize() {
    // Do nothing.
    // It will automatically trigger to update the bound properties in template.
  }
}


example.component.css

tr.sticky {
  top: 60px;
  position: fixed;
  z-index: 99;
}

0

你可以使用JavaScript获取任何列的宽度,然后将其设置为固定或绝对位置的标题,也可以使用HTML和代码:

<div class="table-wrapper content">
  <!-- overall wrapper -->
  <table>
    <!-- header -->
    <thead>
      <tr>
        <th>Header 1</th>
        <th>Header 2</th>
        <th>Header 3</th>
      </tr>
    </thead>
  </table>
</div>
<div class="table-body-wrapper" style="position: relative; overflow: visible;">
  <!-- the element with the custom scrollbar -->
  <table>
    <!-- body -->
    <tbody>
      <!-- auto-generated data (see js function below) -->
      <tr>
        <td>Row 1, Column 1</td>
        <td>Row 1, Column 2</td>
        <td>Row 1, Column 3</td>
      </tr>
      <tr>
        <td>Row 2, Column 1</td>
        <td>Row 2, Column 2</td>
        <td>Row 2, Column 3</td>
      </tr>
      <tr>
        <td>Row 3, Column 1</td>
        <td>Row 3, Column 2</td>
        <td>Row 3, Column 3</td>
      </tr>
      <tr>
        <td>Row 4, Column 1</td>
        <td>Row 4, Column 2</td>
        <td>Row 4, Column 3</td>
      </tr>
      <tr>
        <td>Row 5, Column 1</td>
        <td>Row 5, Column 2</td>
        <td>Row 5, Column 3</td>
      </tr>
    </tbody>
  </table>
</div>

我不理解这个答案 - 是否有什么遗漏? - Asger Vestbjerg
我能为您做些什么? - Morteza Fathnia
哥们儿... 你忘记粘贴你的 JS 函数了! - C4d
好的,我忘记了,但我会重新阅读并完成它。抱歉,谢谢! - Morteza Fathnia

-1

遗憾的是,在大多数现代浏览器中,“sticky”在“thead”或“tr”上不起作用。 - ESWAT
是的,请在 https://caniuse.com/#search=sticky 上检查是否与您的流量UA匹配。 - Thomas Decaux
1
请删除CodePen链接,它是错误的,并且没有使用您所说的内容。 - Jindra Vysocký

-1

我认为你不需要使用Angular指令,因为它会覆盖样式,当添加“stick”类时,会指定宽度。

你可以直接固定表头的位置,并在其上设置更高的z-index,这样当滚动时,主体部分就不会显示出来。

请参考Codepen示例:

thead{
      position:fixed;
      z-index:2;
      ...
     }

tbody{
      position:absolute;
      z-index:1;
      ...
     }

https://codepen.io/ciammarino/pen/vmqzLL


问题在于如何将正文列的宽度与标题列的宽度“同步”。你已经通过 CSS 对其进行了硬编码。 - Thomas Decaux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接