当前位置: 首页 > news >正文

手撸一个Table组件(Table组件不过如此)

一、前言

手写Table组件这个文章我一直都想写,今天终于得空来写它了。小编认为Table组件是组件库里"较为复杂"的一个组件,因为它的扩展性非常强,并且它的基础样式如何去写都非常考究,那么今天我就带大家来实现一个基础功能的table组件,废话不多bb,进入正题吧。

二、实现哪些功能?

  • 最基础的table布局
  • 固定头
  • 固定列

三、实现的效果

以及组件的使用方式期望是这样:

const column = [{ name: '序号', key: 'order', width: '100px', isFixed: true },{ name: '第二列', key: 'col2', width: '200px' },{ name: '第三列', key: 'col3', width: '300px' },{ name: '第四列', key: 'col4', width: '200px' },{ name: '第五列', key: 'col5', width: '500px' },{ name: '第六列', key: 'col6', width: '200px' },
];
const data = [{ order: 1, col2: '1-2', col3: '1-3', col4: '1-4', col5: '1-5', col6: '1-6' },{ order: 2, col2: '2-2', col3: '2-3', col4: '2-4', col5: '2-5', col6: '2-6' },{ order: 3, col2: '3-2', col3: '3-3', col4: '3-4', col5: '3-5', col6: '3-6' },{ order: 4, col2: '4-2', col3: '4-3', col4: '4-4', col5: '4-5', col6: '4-6' },{ order: 5, col2: '5-2', col3: '5-3', col4: '5-4', col5: '5-5', col6: '5-6' }
];
<CustomTablecolumn = { column } data = { data } rowHeight = { '100px' } /> 

四、动手实现

4.1、table组件的尺寸

4.1.1、如何定义table组件的宽?

对于table组件来说,定义宽度有2种方式,一种是"固定宽度布局",另一种是"自由宽度布局"。我们可以通过"table-layout"属性在这2种方式中做出选择。

4.1.1.1、“固定宽度布局”

就是显示的定义table标签的宽度(即table-layout: fixed),那么此时 <table> 的宽度 与 各列 [td | th] 的宽度的关系如下:

  • table真实的width = Math.max(table.style.width, 各列宽度之和)
  • 如果 table.style.width > 各列宽度之和,那么二者之差再除以列数得到的结果将增加到各列上。

纸上得来终觉浅,我们来跑下代码加深一下上述节论的记忆(以下均是react环境下的代码):

table {table-layout: fixed;border-collapse: collapse;border-spacing: 0px;width: 200px;
} 
<div className = 'yon-table-box'><table><colgroup><col style={{ width: '100px' }}><col style={{ width: '100px' }}><col style={{ width: '100px' }}><colgroup><thead><th>列1</th><th>列2</th><th>列3</th></thead></table>
</div> 

此时效果如下:

此时我们再稍微改动下样式,css如下:

table {table-layout: fixed;width: 500px;border-collapse: collspse;border-spacing: 0px;
} 

效果如下:

此时我们发现,上述结论是对的。

4.1.1.2、“自由宽度布局”

顾名思义,更容易实现这个等式 “table.style.width == 各列宽度之和 + 边框 + 间距”。通过设置 table-layout: auto 来触发。

我们来跑下代码试一下:

table {table-layout: auto;border-collapse: collapse;border-spacing: 0px;width: auto;
} 
<div className = 'table-box'><table><colgroup><col style={{ width: '100px' }}><col style={{ width: '100px' }}><col style={{ width: '100px' }}></colgroup><thead><th>列1</th><th>列2</th><th>列3</th></thead></table>
</div> 

此时我们来看下效果:

4.1.1.3、table宽度的最终选择

经过上面2种布局的分析,我们决定选用"自由宽度布局"的方式定义table的宽度,此时咱们的CustomTable组件的代码如下:

 .yon-table-box {width: 100px;height: 100px;overflow: scroll;}table {table-layout: auto;table-collapse: collapse;table-spacing: 0px;width: auto;}th {background: #f4f4f4;} 
 import React from 'react';class CustomTable extends React.Component {constructor(props){super(props)}render (){const { column } = this.props;return <div className = 'yon-table-box'><div className = 'right'><table><colgroup>{column.map(colItem => {return <col style={{ colItem.width }}>})}</colgroup><thead><tr>{column.map(colItem => {return <th>{ colItem.name }</th>})}</tr></thead></table></div></div>}} 

Table的使用:

 import React from 'react';const column = [{ name: '列1', key: 'col1', width: '100px' },{ name: '列2', key: 'col2', width: '200px' },{ name: '列3', key: 'col3', width: '300px' },];<CustomTable column = { column } /> 

4.1.2、如何定义table组件的高?

定义table组件的行高度,这个就比较简单了,我们只需要保证 table.style.height = ‘auto’, 即可实现自定义行高,CustomTable组件的代码如下:

 .yon-table-box {width: 100px;height: 100px;overflow: scroll;}table {table-layout: auto;table-collapse: collapse;table-spacing: 0px;width: auto;// 新增代码+++++++++++++++++++++height: auto;}th {background: #f4f4f4;}// 新增代码++++++++++++++++++++++++++td {background: #fff;border-bottom: 1px solid rgb(208, 208, 208);} 
 import React from 'react';class CustomTable extends React.Component {constructor(props){super(props)}render (){const { column, data, rowHeight } = this.props;return <div className = 'yon-table-box'><div className = 'right'><table><colgroup>{column.map(colItem => {return <col style={{ colItem.width }}>})}</colgroup><thead><tr>{column.map(colItem => {return <th>{ colItem.name }</th>})}</tr></thead><tbody>{// 新增代码+++++++++++++++++++++++++data.map(dataItem => {return <tr>{column.map(colItem => {return <td style={{ height: rowHeight }}>{dataItem[colItem.key]}</td>})}</tr>})}</tbody></table></div></div>}} 

好啦,此时咱们的第一个功能到这就算实现啦,如果你是一步一步跟下来的,那么此时的效果应该是这样的:

4.2、固定列

我们先来看一下下面的图:

首先,根据目前实现的效果来看,我们可以得出以下信息:

  • 目前dom上就只有一个table,意味着 表头、表体是连着的,符合正常文档流所有的特点。
  • 红色框是我们想要固定的列。

好,此时我们来想一下能够做到固定列(无非是2个div互不干扰呗)的方法有哪些?

4.2.1、方式一

把一个table分为左右2个table,并保证只有右侧的table局部滚动,干掉父div的scroll。

4.2.2、方式二

依旧是一个table分为左右2个table,只是在不改变现在滚动的情况下,给左侧的table新增一个"sticky"的粘性定位即可。

4.2.3、方式三

利用js,监听scroll事件,在滚动的时候,利用transform属性,动态的设置translateX,来达到固定列的效果

4.2.3、固定列的最终选择

这里我们选择 方式二。理由非常简单,改动量非常少的情况就可以实现,其他的2种情况的改动都挺大,但是也可以实现,下面我会把其他的2种方式的伪代码写出来供大家参考。

  • 方式一。其实这种方式更适合"固定宽度布局"的table,因为这种table的width是非常容易拿到的,你只需要保证列数过多的时候出现滚动条就可以(也仅仅是一行样式的问题),伪代码如下:
 import React from 'react';export default class App extends React.Component {constructor(props){super(props)}render (){return <div style={{ display: 'flex' }}><!-- 左侧固定列 --><div className = 'left'><table></table></div><!-- 右侧自由列 --><div className = 'right' style={{ overflow: 'scroll' }}><table></table></div></div>}} 
  • 方式三。这种利用js的方式是最看重代码结构的,而且还会使你的代码变得非常臃肿(不利于拆分),它比较适用于下面的写法:
 import React from 'react';// 大家看到这样的写法其实可能感觉不到什么,但是如果这样写的话,table组件的抽取将会异常困难。class App extends React.Component {constructor(props){super(props)this.leftTableRef = React.createRef();this.scrollTableBox = React.createRef();}scrollTable = () => {// 保持左侧固定不动this.leftTableRef.current.style.transform = `translateX(-${this.scrollTableBox.current.scrollLeft}`;}render (){return <div ref = { this.scrollTableBox } style={{ display: 'flex', overflow: 'scroll' }} onScroll = { () => this.scrollTable() }><!-- 左侧固定列table --><table ref={ this.leftTableRef }></table><!-- 右侧自由列table --><table></table></div>}} 

4.2.4、固定列的最终代码

 .yon-table-box {width: 100px;height: 100px;overflow: scroll;}table {table-layout: auto;table-collapse: collapse;table-spacing: 0px;width: auto;// 新增代码+++++++++++++++++++++height: auto;} th { background: #f4f4f4;} // 新增代码++++++++++++++++++++++++++td {background: #fff;border-bottom: 1px solid rgb(208, 208, 208);}// 新增代码++++++++++++++++++++++++++.left {position: sticky;left: 0px;} 
 import React from 'react';class CustomTable extends React.Component {constructor(props){super(props)this.state = {// 固定列集合fixedColumnArr : [];// 自由列集合notFixedColumnArr: [];}}componentDidMount(){const { column } = this.props;this.setState(state => {return {// column配置项中,isFixed用于标识是否是固定列fixedColumnArr : column.filter(item => item.isFixed),notFixedColumnArr: column.filter(item => !item.isFixed)}})}render (){const { data, column, rowHeight } = this.props;const { fixedColumnArr, notFixedColumnArr } = this.state;return <div className = 'yon-table-box'>{ fixedColumnArr.length > 0&& <div className = 'left'> <table> <colgroup> { fixedColumnArr.map(item => { return <col style={{ minWidth: item.width, width: item.width }}> }) } </colgroup> <thead> <tr> { fixedColumnArr.map(item => { return <th>{item.name}</th> }) } </tr> </thead> <tbody> { data.map(dataItem => { return <tr> { fixedColumnArr.map(colItem => { return <td>{dataItem[colItem.key]}</td> }) } </tr> }) } </tbody> </table> </div>}<div className = 'right'><!-- 跟left代码一样,只需要把 fixedColumnArr 换成 notFixedColumnArr 即可 --></div></div>}} 

4.3、固定头

固定头的实现思路 其实和 固定列的思路是一样的,这里就不具体分析了,夜也深了,哈哈哈,这里我就偷点懒,给伪代码了:

 import React from 'react';class CustomTable extends React.Component {constructor(props){super(props)this.state = {// 固定列集合fixedColumnArr : [];// 自由列集合notFixedColumnArr: [];}}render (){const { data, column, rowHeight } = this.props;return <div className = 'yon-table-box'>// 整张表的头部(整个头部是需要sticky的)<div className = 'top'><div className = 'left'></div><div className = 'right'></div></div>// 整张表的body(左侧需要固定的body是需要sticky的)<div className = 'bottom'><div className = 'left'></div><div className = 'right'></div></div></div>}} 

五、最后

好啦,table组件这次就分享到这里了,文章里有讲的不对的地方,欢迎大家指正,如果大家对table组件的实现有什么好的想法,也欢迎评论留言,那么886~~~

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

相关文章:

手撸一个Table组件(Table组件不过如此)

一、前言 手写Table组件这个文章我一直都想写&#xff0c;今天终于得空来写它了。小编认为Table组件是组件库里"较为复杂"的一个组件&#xff0c;因为它的扩展性非常强&#xff0c;并且它的基础样式如何去写都非常考究&#xff0c;那么今天我就带大家来实现一个基础…...

Python|Leetcode刷题日寄Part01

Python|Leetcode刷题日寄Part0101&#xff1a;两数之和02&#xff1a;无重复字符的最长子串03&#xff1a;两数相加04&#xff1a;反转链表05&#xff1a;有效的括号06&#xff1a;回文数07&#xff1a;删除有序数组中的重复项08&#xff1a;删除链表的倒数第N个结点09&#xf…...

微信小程序更改头像昵称

背景 前面写了一篇关于小程序头像昵称获取更改的方案&#xff0c;有很多小伙伴私信我发一个整体的逻辑思路&#xff01; 解决思路 前面的这篇文章中我们给出了页面中获取头像昵称的代码&#xff1a; <view class"headInfo" data-weui-theme"{{theme}}&qu…...

Linux 基础知识之文件系统

目录一、文件系统1.文件种类2.Linux和Windows文件后缀的不同3.查看文件类型3.绝对路径与相对路径二、系统分区三、目录结构一、文件系统 1.文件种类 Linux中一切皆文件。目光所及&#xff0c;皆是文件。文件的种类共有七种&#xff0c;每种文件都有自己的独特标识&#xff1a;…...

LeetCode 36. 有效的数独

LeetCode 36. 有效的数独 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 请你判断一个 9x99 x 99x9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1−91-91−9 在每一行只能出现一次。数字 1−91-91−9 在每一列…...

2023-02-22 cascades-columbia-核心处理记录

摘要: columbia是哥伦比亚对于cascades的一个改进, 并且paper写的也相对详尽. 虽然cacades的实现有很多,比较出名的就是greenplum的gporca, 不过columbia也有其显著的优点. 本文通过对columbia的分析展开对cascades优化器思想的探讨. 参考: 2023-02-10 哥伦比亚cascades-xu-…...

华为分布式存储(FusionStorage)

Server SAN SAN&#xff1a;存储区域网络 IP SAN&#xff1a;以太网交换机和普通网线连接的存储&#xff0c;交换机之间做堆叠FC SAN&#xff1a;FC&#xff08;光纤&#xff09;交换机和光纤连接的存储&#xff0c;交换机之间做级联Server SAN&#xff1a;可以使用以太网交换机…...

说说 React 中 fiber、DOM、ReactElement、实例对象之间的引用关系

原生组件 fiber 原生组件 fiber&#xff0c;指的就是 type 为 “span”、“div” 的 fiber。 1.fiber.stateNode 指向真实 DOM 节点&#xff1b;2.node["__reactFiber$" randomKey] 指向对应 fiber&#xff0c;使用随机数是防止和业务代码的属性名冲突&#xff0c;…...

LaTex公式使用(Word中的公式编辑,尤其是方程组等联合公式)

文章目录 LaTex公式使用(Word中的公式编辑,尤其是方程组等联合公式)refnotedemoLaTex公式使用(Word中的公式编辑,尤其是方程组等联合公式) ref markdown中公式编辑教程 在 Microsoft Word 中使用 LaTeX 输入数学公式【比较全,介绍了支持的语法和不支持的语法】 用wo…...

S5P6818_系统篇(2)源码编译及烧录

源码获取 源码获取和操作流程 1.下载liunux下的系统制作脚本&#xff0c;可以烧录系统和构建镜像 git clone https://github.com/friendlyarm/sd-fuse_s5p6818.git 如果出现git错误可使用如下方法&#xff1a; git config --global http.sslverify false 2.阅读该工具rea…...

LDPC码的编译码原理简述

关于fpga调用ldpc IP core的相关参数问题可以看我的另一篇文章 LDPC码由Gallager在1962年提出&#xff0c;全称为 Low Density Parity-check Codes 低密度奇偶校验码 它的译码性能可以逼近Shannon信道容量限&#xff0c;广富盛名的Turbo码也被证明是LDPC码的一个特例。并且LDPC…...

网络安全——数链路层据安全协议

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.数据链路层安全协议简介 1.数据链路安全性 二.局域网数据链路层协议 1.…...

spring的启动过程(一) :IOC容器的启动过程

一、web容器的加载 首先我们要先知道一个web项目的启动过程。 将Web项目部署到Tomcat中的方法之一&#xff0c;是部署没有封装到WAR文件中的Web项目。要使用这一方法部署未打包的webapp目录&#xff0c;只要把我们的项目&#xff08;编译好的发布项目&#xff0c;非开发项目&am…...

这次,我的CentOS又ping不通www.baidu.com了(gateway配置)

当我们保证了宿主机与虚拟机的ip地址在同一网段&#xff0c;并且我们使用虚拟机ping宿主机&#xff0c;与宿主机ping虚拟机都可以互相ping通的情况下虚拟机却ping不通外网了&#xff0c;由于涉及到了跨越网络访问&#xff0c;所以我们应该把问题聚焦在网关的配置上&#xff01;…...

启智社区“我为开源狂”第六期活动小白教程之基础活跃榜

一、写在前面 春天来啦~启智社区第六期活动也来啦&#xff01; 有奖金的哦~~ 基础活跃榜奖金根据用户活跃程度进行100-300元的激励。 挑战升级榜需要用户完成相应任务&#xff0c;达标者可获得300-1000元的激励。 邀请助力榜根据用户邀请情况进行积分累加&#xff0c;按实际达…...

华为OD机试 - 区块链文件转储系统(Python)【2023-Q1 新题】

华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 区块链文件转储系…...

【字节面试】Fail-fast知识点相关知识点

字节面试&#xff0c;问到的一个小知识点&#xff0c;这里做一下总结&#xff0c;其实小编之前有一篇文章&#xff0c;已经对此有过涉及&#xff0c;不过这里知识专项针对于问题&#xff0c;把这个知识点拎出来说一下。 1.问题 什么是Fail-fast机制&#xff1f; Hashmap是否拥…...

git应用笔记(三)

在新增虚拟机linux的基础上&#xff0c;做git的下载与提交 1、初始化自己的用户名和邮箱。 git config --global user.name “输入你的用户名” git config --global user.email “输入你的邮箱” 2、将本地公钥及配置如图1复制粘贴到虚拟机当前用户.ssh\目录下 4929a0205f43…...

有序表的应用:设计一个增、删、查数据的时间复杂度均为O(logN)的结构

1、题目描述 设计一个结构包含如下三个方法&#xff1a; void add(int index, int num); //把num加入到index位置 int get(int index); //取出index位置的值&#xff08;是自然序的index位置&#xff0c;非排序后&#xff09; void remove(int index); //把index位置上的值删…...

离线环境拷贝迁移 conda envs 环境(蛮力方法,3行命令)

前言 最近要使用 GPU 服务器做实验&#xff0c;可惜的是&#xff0c;有网络连接的服务器显卡旧&#xff0c;算力不够&#xff1b;显卡较新的机器没有联网。于是有需求将旧机器上配置好的 conda 环境迁移至新机器。网上给的默认方法生成 yaml 文件迁移等 需要联网&#xff0c;只…...

LSTM、GRU与注意力机制在股票预测中的性能对比与实战指南

1. 项目概述与核心价值在量化金融和算法交易这个行当里&#xff0c;预测股票价格走势一直是个充满诱惑又极具挑战的“圣杯”问题。传统的技术分析和基本面分析&#xff0c;虽然各有拥趸&#xff0c;但在面对市场的高噪声、非线性和突发性事件时&#xff0c;往往显得力不从心。我…...

别光看手册!手把手教你读懂气体放电管(GDT)的6个关键参数,选型不踩坑

气体放电管实战选型指南&#xff1a;从参数表到电路设计的6个关键决策点 每次打开气体放电管&#xff08;GDT&#xff09;的英文数据手册&#xff0c;面对密密麻麻的参数表格和波形图&#xff0c;不少工程师都会陷入选择困难——这些数值到底如何影响实际电路保护效果&#xf…...

为什么你的DeepSeek沙箱被绕过了?揭秘3种未公开的上下文逃逸技术及熔断防护配置

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;DeepSeek沙箱安全机制概述 DeepSeek沙箱是一种面向大语言模型推理环境的轻量级隔离执行框架&#xff0c;旨在防止恶意代码逃逸、资源滥用及敏感数据泄露。其核心设计遵循最小权限原则与强边界隔离策略&#xf…...

Awoo Installer:如何用这个免费工具快速安装Switch游戏

Awoo Installer&#xff1a;如何用这个免费工具快速安装Switch游戏 【免费下载链接】Awoo-Installer A No-Bullshit NSP, NSZ, XCI, and XCZ Installer for Nintendo Switch 项目地址: https://gitcode.com/gh_mirrors/aw/Awoo-Installer Awoo Installer是一款专为Ninte…...

深度解析Atmosphere系统:为Nintendo Switch带来的完整自定义固件解决方案

深度解析Atmosphere系统&#xff1a;为Nintendo Switch带来的完整自定义固件解决方案 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable 你是否曾为Switch游戏价格高昂而烦恼&#xff1f;是否…...

如何精准识别高校院所与企业之间的潜在合作机会?

核心要点 传统“相亲角”式校企对接效率低下&#xff0c;根源在于科研供给与市场需求间的信息断层&#xff0c;必须转向以数据驱动、模型研判为核心的精准识别机制&#xff0c;才能将模糊的产学研线索转化为可落地的合作机会。精准识别合作机会的关键在于分拆为“供给侧”与“需…...

STM32F407 ADC采样值跳得厉害?HAL库时钟配置与软件滤波避坑指南

STM32F407 ADC采样值跳得厉害&#xff1f;HAL库时钟配置与软件滤波避坑指南 在嵌入式系统开发中&#xff0c;ADC&#xff08;模数转换器&#xff09;的稳定性直接关系到整个系统的测量精度。特别是对于STM32F407这类高性能MCU&#xff0c;当应用于电源监控、医疗设备或工业传感…...

如何高效使用智能手机号码定位工具:开源解决方案全指南

如何高效使用智能手机号码定位工具&#xff1a;开源解决方案全指南 【免费下载链接】location-to-phone-number This a project to search a location of a specified phone number, and locate the map to the phone number location. 项目地址: https://gitcode.com/gh_mir…...

Kali Web渗透实战:从登录接口到管理员后台的完整链路

1. 这不是Kali的安装教程&#xff0c;而是Web渗透测试者的真实工作切片“精通 Kali Linux Web 渗透测试”——这个标题在各大技术社区里出现频率极高&#xff0c;但绝大多数内容要么是Kali系统安装基础命令罗列&#xff0c;要么是照搬OWASP Top 10概念空谈原理&#xff0c;真正…...

Google I/O 2026 | 开发者主题演讲精华集锦

作者 / Google I/O 团队AI 已不再只是提供辅助&#xff0c;而是迈向了能够在整个工作流中独立处理复杂任务的智能体阶段。在今年的 I/O 大会上&#xff0c;我们发布了 Gemini 3.5 系列模型&#xff0c;并升级了我们的 "智能体优先" 式开发平台 Antigravity&#xff0…...