关于前端:使用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外面设置就行。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理