react0.14+jquery固定表头表格

news/2025/10/29 10:25:37/文章来源:https://www.cnblogs.com/chaiys/p/19173605

代码文件index.js如下:

// index.js
import React, { Component, PropTypes } from 'react';
import $ from 'jquery';
import './style.less';export default class CommonTable extends Component {static propTypes = {columns: PropTypes.array.isRequired,data: PropTypes.array.isRequired,height: PropTypes.number,rowHeight: PropTypes.number,className: PropTypes.string};static defaultProps = {height: 300,rowHeight: 36,className: '',};constructor(props) {super(props);this.state = {scrollbarHeight: 0,}}componentDidMount() {this._bindEvents();this._applyColumnWidths();this._syncScrollPositions(); // 初始同步}componentDidUpdate() {this._applyColumnWidths();this._syncScrollPositions();}componentWillUnmount() {this._unbindEvents();}_bindEvents() {const $body = $(this.refs.body);const $headerInner = $(this.refs.headerInner);const $scrollbar = $(this.refs.scrollbar);// 表体滚动时,header与底部滚动条同步$body.on('scroll.commonTable', () => {const left = $body.scrollLeft();$headerInner.css('margin-left', -left);$scrollbar.scrollLeft(left);});// 底部滚动条滚动时,body与header同步$scrollbar.on('scroll.commonTable', () => {const left = $scrollbar.scrollLeft();$headerInner.css('margin-left', -left);$body.scrollLeft(left);});$(window).on('resize.commonTable', () => this._applyColumnWidths());}_unbindEvents() {$(this.refs.body).off('.commonTable');$(this.refs.scrollbar).off('.commonTable');$(window).off('resize.commonTable');}_syncScrollPositions() {// 保证三者初始 scrollLeft 一致const $body = $(this.refs.body);const $scrollbar = $(this.refs.scrollbar);const $headerInner = $(this.refs.headerInner);const left = $body.scrollLeft() || $scrollbar.scrollLeft() || 0;$body.scrollLeft(left);$scrollbar.scrollLeft(left);$headerInner.css('margin-left', -left);}_applyColumnWidths2() {const cols = this.props.columns;const $headerRow = $(this.refs.headerRow);const $bodyTable = $(this.refs.bodyTable);const $bodyRows = $bodyTable.find('tr.ct-row');const containerWidth = $(this.refs.container).innerWidth();// 计算固定列宽和可伸缩列数let totalFixed = 0;let flexibleCount = 0;cols.forEach(col => {if (typeof col.width === 'number') totalFixed += col.width;else flexibleCount++;});let finalWidths = [];if (totalFixed >= containerWidth) {// 总列宽超过容器,固定列宽 + 横向滚动finalWidths = cols.map(col =>typeof col.width === 'number' ? col.width : 100);$(this.refs.body).css({ overflowX: 'auto' });if (this.state.scrollbarHeight === 0) {this.setState({ scrollbarHeight: 16 });}} else {// 列少,均分剩余空间const remaining = containerWidth - totalFixed;const flexWidth = flexibleCount > 0 ? Math.floor(remaining / flexibleCount) : 0;finalWidths = cols.map(col =>typeof col.width === 'number' ? col.width : flexWidth);$(this.refs.body).css({ overflowX: 'hidden' });if (this.state.scrollbarHeight === 16) {this.setState({ scrollbarHeight: 0 });}}const totalWidth = finalWidths.reduce((a, b) => a + b, 0);// 设置表格宽度等于容器宽度$bodyTable.css({ tableLayout: 'fixed', width: containerWidth });$(this.refs.headerRow).closest('table').css({ tableLayout: 'fixed', width: containerWidth });// 设置表头列宽$headerRow.find('th').each(function (idx) {$(this).css({ width: finalWidths[idx], boxSizing: 'border-box' });});// 设置表体所有 td 列宽$bodyRows.each(function () {$(this).find('td').each(function (idx) {$(this).css({ width: finalWidths[idx], boxSizing: 'border-box' });});});// 底部滚动条宽度$(this.refs.scrollbarInner).css({ width: totalWidth, height: 1 });}_applyColumnWidths() {const cols = this.props.columns;const $headerRow = $(this.refs.headerRow);const $bodyTable = $(this.refs.bodyTable);const $bodyRows = $bodyTable.find('tr.ct-row');const containerWidth = $(this.refs.container).innerWidth();// 计算固定列宽和可伸缩列数(只算非 fixedWidth 列)let totalFixed = 0;let flexibleCount = 0;cols.forEach(col => {if (!!col.fixedWidth || typeof col.width === 'number') totalFixed += col.width || 100;else flexibleCount++;});let finalWidths = [];if (totalFixed >= containerWidth) {// 总列宽超过容器,固定列宽 + 横向滚动finalWidths = cols.map(col => {if (!!col.fixedWidth || typeof col.width === 'number') return col.width;return 100; // 默认宽度});$(this.refs.body).css({ overflowX: 'auto' });if (this.state.scrollbarHeight === 0) this.setState({ scrollbarHeight: 16 });} else {// 列少,均分剩余空间const remaining = containerWidth - totalFixed;const flexWidth = flexibleCount > 0 ? Math.floor(remaining / flexibleCount) : 0;finalWidths = cols.map(col => {if (!!col.fixedWidth || typeof col.width === 'number') return col.width;return flexWidth;});$(this.refs.body).css({ overflowX: 'hidden' });if (this.state.scrollbarHeight === 16) this.setState({ scrollbarHeight: 0 });}const totalWidth = finalWidths.reduce((a, b) => a + b, 0);// 设置表格宽度等于容器宽度$bodyTable.css({ tableLayout: 'fixed', width: containerWidth });$(this.refs.headerRow).closest('table').css({ tableLayout: 'fixed', width: containerWidth });// 应用列宽到表头$headerRow.find('th').each(function (idx) {$(this).css({ width: finalWidths[idx], boxSizing: 'border-box' });});// 应用列宽到表体所有 td$bodyRows.each(function () {$(this).find('td').each(function (idx) {$(this).css({ width: finalWidths[idx], boxSizing: 'border-box' });});});// 底部滚动条宽度$(this.refs.scrollbarInner).css({ width: totalWidth, height: 1 });}renderHeader() {const { columns } = this.props;return (<table className="ct-table ct-header-table" ref="headerTable"><thead><tr ref="headerRow">{columns.map(col => (<thkey={col.key || col.dataIndex}title={col.title || col.key || col.dataIndex}className="ct-cell"style={{ textAlign: col.align ? col.align : 'center' }}>{col.title || col.key || col.dataIndex}</th>))}</tr></thead></table>);}renderBody() {const { data, columns, rowHeight } = this.props;return (<table className="ct-table ct-body-table" ref="bodyTable"><tbody>{data.map((row, rIdx) => (<tr className="ct-row" key={rIdx} style={{ height: rowHeight }}>{columns.map(col => (<tdkey={col.key || col.dataIndex}className="ct-cell"title={row[col.key || col.dataIndex] != null ? String(row[col.key || col.dataIndex]) : ''}style={{ textAlign: col.align ? col.align : 'left' }}>{col.render? col.render(row[col.key || col.dataIndex], row, rIdx): row[col.key || col.dataIndex]}</td>))}</tr>))}</tbody></table>);}render() {const { className, height } = this.props;const { scrollbarHeight = 16 } = this.state; // 底部横向滚动条高度const headerHeight = 36; // 表头固定高度// 表体高度 = 总高度 - 表头 - 底部滚动条const bodyHeight = height - headerHeight - scrollbarHeight;return (<div className={`common-table ${className}`} ref="container" style={{ height }}><div className="ct-header-outer" style={{ height: headerHeight }}><div className="ct-header-inner" ref="headerInner">{this.renderHeader()}</div></div>{/* 表体 + 底部滚动条占位布局 */}<div className="ct-body-scroll-wrapper" style={{ height: bodyHeight + scrollbarHeight }}><divclassName="ct-body-outer"ref="body"style={{ height: bodyHeight, overflowY: 'auto', overflowX: 'auto' }}>{this.renderBody()}</div>{/* 底部滚动条占位 */}<div className="ct-scrollbar" ref="scrollbar" style={{ height: scrollbarHeight }}><div className="ct-scrollbar-inner" ref="scrollbarInner" /></div></div></div>);}
}

样式style.less如下:

.common-table {position: relative;width: 100%;font-family: Arial, Helvetica, sans-serif;border: 1px solid #DFE1E6;background: #fff;
}.ct-header-outer {background: #fff;border-bottom: 1px solid #DFE1E6;overflow: hidden;
}.ct-header-inner {width: 100%;transition: margin-left 0.05s linear;
}/* 包裹表体和底部滚动条,使用占位,不覆盖表体内容 */
.ct-body-scroll-wrapper {position: relative;width: 100%;display: flex;flex-direction: column;
}/* 表体 */
.ct-body-outer {width: 100%;overflow-y: auto;overflow-x: auto;flex-shrink: 0;
}/* 隐藏 body 自带水平滚动条,但显示竖向滚动条 */
.ct-body-outer::-webkit-scrollbar {width: 8px;height: 0; /* 隐藏水平滚动条 */
}
.ct-body-outer::-webkit-scrollbar-thumb {background: #dddddd;border-radius: 6px;border: 1px solid #dddddd;
}
.ct-body-outer::-webkit-scrollbar-track {background: transparent;
}
.ct-body-outer {scrollbar-width: auto;-ms-overflow-style: auto;
}.ct-table {border-collapse: collapse;width: 100%;table-layout: fixed;
}.ct-header-table th {padding: 8px 10px;border-right: 1px solid #DFE1E6;background: #E9EBF0;box-sizing: border-box;font-size: 14px;color: #333333;text-align: center;line-height: 20px;font-weight: 400;
}.ct-body-table td {padding: 8px 10px;border-right: 1px solid #DFE1E6;border-bottom: 1px solid #E9EBF0;box-sizing: border-box;font-size: 14px;color: #333333;line-height: 20px;font-weight: 400;
}.ct-cell {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;cursor: default;
}/* 底部滚动条不再绝对定位,占位在表体下方 */
.ct-scrollbar {width: 100%;overflow-x: scroll;overflow-y: hidden;background: #fafafa;border-top: 1px solid #ddd;flex-shrink: 0;height: 16px;
}.ct-scrollbar-inner {height: 1px;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/949590.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年新疆租车公司权威推荐榜单:新疆自驾游租车/新疆乌鲁木齐租车/新疆租皮卡车源头服务商精选

随着新疆旅游热度不断攀升,2024年全区接待游客总量突破2.5亿人次,创下历史新高,直接推动了汽车租赁需求的快速增长。汽车租赁服务以其灵活性高、车型选择多、用车成本可控等优势,成为越来越多游客和商务人士在新疆…

芜湖,千兆网络下载速率只有10MB秒,过的什么苦日子

📝 故事开端:老Mac的重生之旅(与百度网盘的“爱恨情仇”) 我最近决定给我那台老款MacBook Pro来个“系统大扫除”。第一步嘛,当然是下载系统镜像。这事儿听起来简单,网上搜“苹果系统之家”,找到对应版本,点击…

从“能用”到“好用”:兰亭妙微谈小程序设计的5个高转化秘诀

从“能用”到“好用”:兰亭妙微谈小程序设计的5个高转化秘诀从能用,到好用:小程序进化的关键一步 在数字化浪潮中,小程序已然成为企业连接用户的关键桥梁。起初,小程序只要 “能用”,能实现基本功能,满足用户最…

2025 年固定式探伤室,大型辐射防护探伤室,移动式探伤室厂家最新推荐,产能、专利、环保三维数据透视

引言 在航空航天、石油化工等高端制造领域,固定式、大型辐射防护及移动式探伤室作为无损检测核心设施,其防护合规性与设备适配性直接决定生产安全与检测精度。据中国无损检测协会 2025 年专项测评数据显示,当前市场…

2025 年辐射防护探伤室,工业射线探伤室,焊接工艺探伤室厂家最新推荐,资质、案例、售后三维透视与选购指南!

引言 在航空航天、石油化工、压力容器等高端制造领域,辐射防护、工业射线及焊接工艺探伤室是保障检测安全与产品精度的核心设施。随着《工业 x 射线探伤室辐射屏蔽规范》(GBZ/T250-2014)等标准执行趋严,市场对探伤…

2025年比较好的低温压榨粮油厂家推荐及采购指南

2025年比较好的低温压榨粮油厂家推荐及采购指南随着健康饮食理念的普及,低温压榨食用油因其保留更多营养成分、不破坏天然活性物质等特点,越来越受到消费者的青睐。2025年,低温压榨粮油市场将迎来更广阔的发展空间。…

2025 年工业探伤室,组合式探伤室,X 射线探伤室,γ 射线探伤室厂家最新推荐,实力品牌深度解析采购无忧之选!

引言 在航空航天、石化装备、压力容器等高端制造领域,探伤室作为无损检测核心场所,其防护合规性与检测适配性直接决定生产安全与产品精度。当前市场呈现 “新旧品牌并存” 格局,部分厂家存在铅板纯度不足、环评支持…

数据驱动的DevOps:如何通过一体化平台破解研发协同效率瓶颈?

企业研发面临协同低效难题,传统工具链易致数据孤岛,选择能打通数据、实现端到端可视化的一体化DevOps平台是关键,国产DevOps平台可助力减少协同损耗,有效提升研发效能,为企业突破效率瓶颈提供支撑。在数字化竞争日…

2025 年集成式污水处理设备,养殖污水处理设备,重金属污水处理设备,絮凝沉淀污水处理设备厂家最新推荐,资质、案例、性能三维数据透视

引言 在排污标准持续收紧的背景下,集成式、养殖、重金属及絮凝沉淀等专项污水处理设备成为企业合规运营的核心装备。本次推荐基于行业协会最新测评数据,采用 “资质可信度 — 案例匹配度 — 核心性能参数” 三维评估…

2025年口碑好的钢木课桌椅厂家实力及用户口碑排行榜

2025年口碑好的钢木课桌椅厂家实力及用户口碑排行榜在当今教育装备行业快速发展的背景下,钢木课桌椅作为学校基础教学设施的重要组成部分,其品质直接影响学生的学习体验和健康。随着家长和学校对教育环境要求的不断提…

2025 年 VOC 废气污水处理设备,粪便污水处理设备,锅炉脱硫脱硝污水处理设备厂家最新推荐,产能、专利、环保三维数据透视!

引言 2025 年环保提标改造进入关键阶段,VOC 废气、粪便、锅炉脱硫脱硝等专项污水处理需求激增,设备选型成为企业与项目方的核心难题。本次推荐基于行业协会最新测评数据,采用产能规模、专利技术、环保效能三维评估体…

2025年比较好的机械重型纸箱厂家最新权威实力榜

2025年比较好的机械重型纸箱厂家最新权威实力榜 在工业制造与物流运输领域,重型纸箱作为关键防护包装材料,其质量与性能直接影响设备安全与运输效率。2025年,随着智能制造与绿色包装需求的升级,具备高强度、定制化…

2025 年除尘污水处理设备,一体化污水处理设备,智能化污水处理设备厂家最新推荐,产能、专利、环保三维数据透视

引言 随着环保监管日趋严格,除尘、一体化、智能化污水处理设备需求持续攀升,但市场产品质量参差不齐,选型难题凸显。本次测评依托全国城市工业品贸易中心联合会 T/QGCML 5024—2025《一体化污水处理设备》团体标准,…

2025年广州沥青施工公司权威推荐:沥青路面修补施工/沥青施工/沥青路面摊铺/彩色沥青施工源头施工企业精选

广州作为粤港澳大湾区的核心城市,其城市基础设施建设与维护市场持续活跃。沥青路面施工作为道路建设的重要环节,其工艺质量直接关系到道路使用寿命和行车安全。 近年来,随着广州城市更新进程的加快以及道路交通网络…

半结构化数据表头解析vlm方案

走vlm需要将excel 转换成 pdf 存在一个问题: 当表头过长时,转换后会被分页 因此需要设置参数手动调整 解决方案:https://www.e-iceblue.com/Tutorials/Python/Spire.XLS-for-Python/Program-Guide/Conversion/Pytho…

2025年靠谱的新中式全品类五金厂家实力及用户口碑排行榜

2025年靠谱的新中式全品类五金厂家实力及用户口碑排行榜 在当今五金行业竞争激烈的市场环境下,选择一家实力雄厚、口碑优良的五金供应商至关重要。新中式风格近年来在家居、建筑及装修领域广受欢迎,因此,具备全品类…

2025年质量好的超薄型防火涂料厂家最新权威实力榜

2025年质量好的超薄型防火涂料厂家最新权威实力榜在建筑安全领域,防火涂料作为被动防火系统的重要组成部分,其性能和质量直接关系到建筑结构的耐火极限和人员财产安全。随着2025年建筑防火标准的不断提高,超薄型防火…

2025年评价高的DPA漆雾空气过滤器厂家最新用户好评榜

2025年评价高的DPA漆雾空气过滤器厂家最新用户好评榜在工业生产和环保领域,DPA漆雾空气过滤器是保障空气质量、提升生产环境安全的关键设备。随着环保法规的日益严格和行业需求的增长,选择一家技术领先、服务可靠的过…

2025 年聚氨酯砂浆地坪厂家最新推荐榜,技术实力与市场口碑深度解析的优质品牌筛选

引言 据建筑材料流通协会地坪材料专业委员会 2024 年度测评数据显示,国内聚氨酯砂浆地坪市场品牌合格率仅为 68.3%,部分产品存在耐磨性能不达标、施工后 3 个月内开裂等问题。为帮助企业精准筛选优质品牌,本次推荐榜…

2025年知名的景区冰雕厂家最新推荐权威榜

2025年知名的景区冰雕厂家最新推荐权威榜随着冬季旅游的蓬勃发展,冰雕艺术作为冬季景观的核心元素,越来越受到景区和游客的青睐。优秀的冰雕厂家不仅能打造令人惊叹的冰雪景观,还能为景区带来持续的客流和口碑效应。…