乐趣区

关于前端:使用js和html建立一个头部固定表格

公司有了新的需要,就是须要一个头部固定的表格,查来查去,都感觉很麻烦,罗唆本人写一个好了

如第一幅图所示,成果很好,因为宽度是由浏览器窗口变动的时候通过 js 计算取得,css 仅仅只是设置局部的最小宽度,所以兼容性必定是没有任何问题的。


首先要明确的就是,既然头部须要固定,那么头部和身材必定是分成两个表格来做的,构造如下

<div>
 <div class="table1">
  <table></table>
 </div>
 <div class="table2">
  <table></table>
 </div>
</div>

而后问题来了,因为是两个 table, 那么他们的 td 的宽度是由各自的内容决定的,天然宽度在不通过人为操纵的状况是相对不可能一样的。既然如此,那通过同一个对象治理两个表格,那么宽度天然就雷同了。

先看 ts 代码内容

  tabHead: Array<any> = [{ title: '操作', property: 'checkbox', type: 'checkbox', width: ''},
    {title: '序号', property: 'serial', type: 'serial', width: ''},
    {title: '信息类型', property: 'infoType', type: 'special', children: 'infoTypeChildren', param: 'infoTypeCode', width: '', fackItem:'a'},
    {title: '服务名称', property: 'serviceName', type: 'special', children: 'serviceChildren', param: 'serviceId', width: '', fackItem:'b'},
    {title: "数据起源", property: 'sourceName', type: 'special', children: 'sourceChildren', param: 'dataSourceId', width: '', fackItem:'c'},
    {title: "服务版本", property: 'serviceVersion', width: ''},
    {title: "服务形容", property: 'description', width: ''},
    {title: "注册单位", property: 'register', width: ''},
    {title: "注册工夫", property: 'registerDate', width: ''},
    {title: "服务状态", property: 'status', type: 'state', width: ''},
  ]

下面的是两个 table 共用的对象,其余的字段能够不必理,只须要看 title property width 三个字段就行

再看 html 代码内容

    <div class="table1">
      <table class="service-table" >
        <tr class="head">
          <ng-container *ngFor="let item of tabHead">
            <td [ngStyle]="{'width':item.width}" class="{{item.property}}">
              {{item.title}}
            </td>
          </ng-container>
        </tr>
      </table>
    </div>

这个是头部表格的简化后的代码,利用 angular 的 *ngFor 属性,遍历 tabHead 循环出 td 并且给 td 的款式 width 设置为 tabHeadwidth的值。

      <div class="table2" >
        <table class="service-table">
            <tr *ngFor="let data of tabData;let i = index" #element>
              <ng-container *ngFor="let item of tabHead">
                 <td [ngStyle]="{'width':item.width}" class="{{item.property}}">
                   <span [class]="item.class" [style]="item.style" [innerHTML]="data[item.property]?data[item.property]:'--'"[title]="data[item.property]?data[item.property]:'--'"></span>
                   </td>
              </ng-container>
            </tr>
        </table>
      </div>

同样,这个是身材表格简化后的代码,同样利用 angular 的 *ngFor 属性,遍历 tabHead 循环出 td 并且给 td 的款式 width 设置为 tabHeadwidth的值。不过外层加了一层 tableData 的循环,其字段如下

export class ServiceContentListModel {
    dataSourceId?: string;
    sourceChildren?:Array<any>;
    description?: string;
    id?: string;
    infoType?: string;
    infoTypeCode?: string;
    register?: string;
    registerDate?: string;
    serialNumber?: number;
    serviceId?: string;
    serviceName?: string;
    serviceVersion?: string;
    sourceName?: string;
    status?: string;
    noneed?:boolean=false;
}

简而言之就是 tabHeadproperty会对应 tableData 的字段,而后把对应上的显示到页面上。具体不表


这样一番操作,能够想到两张表格中 td 的宽度都是由同一个对象 tableHead 中的 width 属性决定的了,那么接下来只有通过拿到身材表格每一个 td 的宽度,而后赋值给 tabHead 就行了。

// 因为我应用的是 angular,所以以下代码带有 angular 的个性,当然情理是相通的,用 vue 甚至用原生 js 写法略微变通一下
// 也是能够实现的


@ViewChild('element') navListElement: ElementRef;// 拿到 tr 的 dom 元素

 ngAfterViewInit() {// 在子元素加载实现后执行
    this.setWidth()
    window.onresize = ($event) => {// 浏览器窗口大小变动当前执行
      this.setWidth()}
  }
  
    setWidth() {setTimeout(() => {// 提早一个生命周期后进行,不然在页面渲染实现当前表格还是对不齐状态
      if (this.navListElement) {
        let children = this.navListElement.nativeElement.children;// 拿到一个 tr 中所有 td 的汇合
        let widthSum = 0// 寄存一个 tr 中所有 td 的宽度,用于计算每个 td 所占的百分比
        for (let i = 0; i < this.tabHead.length; i++) {// 每一列宽度换算成像素宽度(除了最初一列)let item = children[i]
          // this.tabHead[i]['width'] = item.offsetWidth + "px"
          widthSum+=item.offsetWidth
        }

        for (let i = 0; i < this.tabHead.length; i++) {// 每一列宽度换算成百分比(除了最初一列)let item = children[i]
          this.tabHead[i]['width'] = (item.offsetWidth/widthSum)*100 + '%'
        }
      }
    });
  }

这样就实现了,具体点的工作,比方设置最小宽度之类的,间接在 css 外面设置就行。

退出移动版