likes
comments
collection
share

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

作者站长头像
站长
· 阅读数 39

前言

又是一个星期新的开始,继续来进行更文。天气逐渐变冷,我来为大家本就寒冷的心送上一份温暖。这次要聊的主题就是:如何使用纯CSS实现可固定表头和固定列的Table表格?

场景

先来说说为什么会想写这么一个主题的文章,主要就是在实际开发工作中,在渲染数据量很大的时候如果我们选用的是AntdTable组件element uiTable组件时,会有一定性能影响,导致界面渲染很慢造成用户体验极差的效果。所以这时候一般会选用虚拟滚动去处理,但是别人写的组件又会存在或多或少的问题,那就要想其他方式去处理需求。

那我一般是选用div来组装成一个表格样式然后再来渲染数据,这样做的好处就是渲染时会很快,不至于造成很差的交互体验。毕竟我们都知道table标签只要一个单元格变化整个表格都会重新渲染,从而造成性能问题。而如果使用div来组装就可以完全避免这样的问题,所以这就是两者最主要的不同。

这里要说明一下,如果渲染数据量很大的时候尽量还是要选用靠谱的虚拟滚动组件去使用,毕竟别人就是为了处理大数据而生的。而这里我提供的div组装成表格的方法适合渲染一两千条以上四五千条以下的数据量,足以满足一般常规数据需求了。如果表格的内容节点很少的话还可以继续往上承载;再如果表格的内容节点多且每一条都含有图片的话那也会需要等待渲染,但相比于使用Antd等框架的Table组件来说,此种方法是足够优异的。

设计思路

下面就来聊聊设计一个可固定表头和固定列的Table表格的思路。先来看看Antd等框架是如何实现的,如果你看过Antd等框架的Table组件的代码,你会发现表头固定的效果使用的是2table标签组装实现的,如下:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

而实现固定列的时候,是使用的position:sticky;实现的,如下:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

那我们又是如何实现呢?那就是只使用position:sticky;就能实现表头固定和列固定效果。也就是不写一行js代码,纯CSS就能实现表格固定的效果。

**sticky**(粘性定位):元素根据正常文档流进行定位,然后相对它的最近滚动祖先和最近块级祖先 ,基于toprightbottom, 和 left的值进行偏移。注意,一个sticky元素会固定在离它最近的一个拥有滚动机制的祖先上(当该祖先的overflow 是 hiddenscrollauto, 或 overlay时),即便这个祖先不是最近的真实可滚动祖先。

其实简单来说**sticky**(粘性定位)可以被认为是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。使用时须指定toprightbottomleft四个阈值其中之一,才可使粘性定位生效,否则其行为与相对定位相同。

好,既然说清楚了我们要用的知识,下面就来开始编码→

开发

下面开发就来分为表头固定列固定,便于理解。首先来创建一个Table.jsx文件:

import React, {useEffect, useState} from 'react';
import './table.less';

/**
 * 表格
 * @constructor
 */
const Table = () => {
  const [dataSource, setDataSource] = useState([]);

  useEffect(() => {
    let arr = []
    for (let i = 0; i < 100; i++) {
      arr.push({
        index: i,
        name: `张三${i}`,
        phone: '130****0000',
        address: '四川省成都市**区**街道**小区**栋',
        tel: '028-1212121',
        time: '2022-11-14'
      })
    }
    setDataSource(arr)
  }, [])

  return(
      <div className="table-container">
          <div className="table">
              <div className="thead">
                  <div className="cell">序号</div>
                  <div className="cell">姓名</div>
                  <div className="cell">联系方式</div>
                  <div className="cell">地址</div>
                  <div className="cell">电话</div>
                  <div className="cell">时间</div>
              </div>
              <div className="tbody">
                  {
                      dataSource.map(v =>
                          <div className="row" key={v.index}>
                              <div className="cell">{v.index}</div>
                              <div className="cell">{v.name}</div>
                              <div className="cell">{v.phone}</div>
                              <div className="cell">{v.address}</div>
                              <div className="cell">{v.tel}</div>
                              <div className="cell">{v.time}</div>
                          </div>
                      )
                  }
              </div>
          </div>
      </div>
  );
};

export default Table;

接着来创建table.less文件:

.table-container {
  .table {
    height: 500px;
    overflow: auto;
    background-color: #fff;
    .thead {
      width: 100%;
      display: flex;
      align-items: center;
      .cell {
        padding: 6px 0;
        font-size: 14px;
        color: #000;
        font-weight: bold;
        border-right: 1px solid #f3f3f3;
        border-bottom: 1px solid #f3f3f3;
        background-color: #fff;
        &:nth-child(1) {
          flex: 0 0 80px;
        }

        &:nth-child(2) {
          flex: 0 0 100px;
        }

        &:nth-child(3) {
          flex: 0 0 120px;
        }

        &:nth-child(4) {
          flex: 1;
        }

        &:nth-child(5) {
          flex: 0 0 100px;
        }

        &:nth-child(6) {
          flex: 0 0 200px;
          border-right: 0;
        }
      }
    }

    .tbody {
      .row {
        display: flex;
        align-items: center;
        .cell {
          padding: 8px 0;
          text-align: center;
          font-size: 12px;
          color: #9F9F9F;
          border-right: 1px solid #f3f3f3;
          border-bottom: 1px solid #f3f3f3;
          background-color: #fff;
          &:nth-child(1) {
            flex: 0 0 80px;
          }

          &:nth-child(2) {
            flex: 0 0 100px;
          }

          &:nth-child(3) {
            flex: 0 0 120px;
          }

          &:nth-child(4) {
            flex: 1;
          }

          &:nth-child(5) {
            flex: 0 0 100px;
          }

          &:nth-child(6) {
            flex: 0 0 200px;
            border-right: 0;
          }
        }
      }
    }
  }
}

这两个文件创建完成之后,运行项目就能得到如下一个图示:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

如上,你就可以得到一个使用div来组装成Table表格的效果了。然而这只是完成了这篇文章的第一步,下面还要来为其增加相应的CSS代码来实现固定表头和固定列的效果。

表头固定

首先表头固定,界面代码结构不需要任何调整,只需要给类名为theaddiv增加一个table-thead-fix类名,如下:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

然后在table.less文件中增加对应的CSS代码,如下:

.table-thead-fix {
  position: sticky;
  top: 0;
  z-index: 99;
}

完成这2步之后,来看看实现的效果,如下:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

看如上的效果动图,还是很完美的把表头给固定住了的,nice!

列固定

接着列固定分为左固定和右固定,如果你想固定的列在左就加上table-cell-fix-left类名;同理如果想固定的列在右就加上table-cell-fix-right类名,表头对应的列也需要加上相同的类名。下面代码是把第一列和最后一列分别左固定和右固定了。如下:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

然后在table.less文件中增加对应的CSS代码,如下:

.table-cell-fix-left {
  position: sticky;
  left: 0;
}

.table-cell-fix-right {
  position: sticky;
  right: 0;
  border-left: 1px solid #f3f3f3;
}

然后为了让表格出现横向滚动条,需要将类名为cell的第4个元素的宽度给加大,不然不会出现横向滚动条(表头和表格内对应的列需要同时更改)。如下:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

这样做完之后,来看最后实现的效果。如下:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

是不是很完美的实现了表格的固定表头和列固定的效果了?简直完美!

注意:如果需要连续固定多列,那就需要给相连的列都给加上左固定或右固定的类名并且得到前一列或几列的宽度来设置leftright值,不然的话你就会出现如下效果:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

后面的会把前面的覆盖掉,所以要解决这个问题,你需要把后续固定列的leftright值给改为前一列的列宽,如下:

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

增加table-cell-fix-left-2的类名,并增加相应的样式代码:

.table-cell-fix-left-2 {
  left: 80px;
  border-left: 1px solid #f3f3f3;
}

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

至此,使用纯CSS实现可固定表头和固定列的Table表格效果就介绍完了。总的来说,代码实现不是很难,只要没有写js的代码都是小case,用此种方法是足以满足稍微大量数据的渲染的,毕竟框架的缺陷上面的叙述中有所提及,就上面的这个数据结构的我试了渲染10000条数据依然没有啥等待,两个字:轻松。所以要杠的就不需要来杠了,有兴趣的可以用Table组件来对比一下两者的优劣就知道了。

最后,如果文章一旦发布我都能预见,肯定会有人要让将其封装为公用组件,没问题的,这一步在慢慢的实现中,毕竟一个功能丰富的表格组件是需要掉很多头发才能完成的,所以静候佳音吧。

后语

小伙伴们,如果觉得本文对你有些许帮助,点个👍或者➕个关注再走呗^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。

使用DIV+纯CSS实现可固定表头和固定列的Table表格效果

转载自:https://juejin.cn/post/7165778919571800077
评论
请登录