当前位置:

js往数组添加新元素

访客 2023-04-17 304 0

react怎么实现表头固定?

React表格固定表头/锁定列

AntDesign的Table组件挺好用,固定表头及锁定列的功能不在话下,但AntDesignMobile没有Table组件。移动端要实现表格固定表头及锁定列的功能应该可以使用rc-table,当然也可以自己写一个。

通过分析AntD的Table,可以看出固定表头的表格是由上下两个<table>标签组成的,它们分别嵌套在div内,上面的是表头,只包含<thead>,下边是表格内容,只包含<tbody>。应该是通过监听下面div的onscroll事件,改变上面div的scrollLeft属性,这样在水平滚动表格时,表头也会同步滚动。固定列是通过设置th及td的CSS属性position为sticky并且设置left或right为0实现,同时设置z-index,让锁定的列始终显示在上方。

原理整明白了,写代码就比较容易了。

components/ScrollableTable/interface.tsximport*asReactfrom'react';exportdeclaretypeAlignType='left'|'center'|'right';exportinterfaceColumnType{align?:AlignType;className?:string;dataKey?:string;fixed?:boolean;title?:React.ReactNode;width?:number;render?:(value:any,record:any,index:number)=>React.ReactNode;}exportinterfaceTableProps{className?:string;style?:React.CSSProperties;columns?:ColumnType[];dataSource?:any[];width?:number;height?:number;}components/ScrollableTable/index.tsximportReact,{FunctionComponent,useRef}from'react';import{TableProps,ColumnType}from'./interface';import'./index.less';constScrollableTable:FunctionComponent<any>=(props:TableProps)=>{conststyle:React.CSSProperties=props.style||{};constmaxHeight:string=props.width?(props.height'px'):'unset';constcolumns:ColumnType[]=props.columns||[];constdataSource:any[]=props.dataSource||[];letmaxWidth:number=0;if(props.width)style.width=props.width;if(columns.length===0){columns.push({dataKey:'key'});}columns.forEach((column:ColumnType)=>{constwidth:number=column.width||50;maxWidth=width;});constfixedColumns:number[][]=getFixedColumns(columns);constleftFixedColumns:number[]=fixedColumns[0];constrightFixedColumns:number[]=fixedColumns[1];consttableBody:any=useRef();consthandleScroll=(target:any)=>{constscrollLeft:number=target.scrollLeft;consttableHeaders:any=target.parentElement.getElementsByClassName('st-table-header');if(tableHeaders.length>0){tableHeaders[0].scrollLeft=scrollLeft;}};return(<divclassName={classNames('st-table-container',props.className)}style={style}><divclassName="st-table-header"><table><colgroup>{renderCols(columns)}</colgroup><theadclassName="st-table-thead"><tr>{columns.map((column:ColumnType,index:number)=>{constalign:any=column.align||undefined;consttitle:React.ReactNode=column.title||'';constfixed:string=leftFixedColumns.includes(index)?'left':(rightFixedColumns.includes(index)?'right':'');constfixedClassName:string=fixed?('st-table-cell-fix-'fixed):'';return(<thkey={index}className={classNames('st-table-cell',fixedClassName,column.className)}style={{textAlign:align}}>{title}</th>);})}</tr></thead></table></div><divref={tableBody}className="st-table-body"style={{maxHeight:maxHeight}}onScroll={(e:any)=>handleScroll(e.currentTarget)}><tablestyle={{width:maxWidth,minWidth:'100%'}}><colgroup>{renderCols(columns)}</colgroup><tbodyclassName="st-table-tbody">{dataSource.map((record:any,index:number)=>(<trkey={index}className="st-table-row">{renderCells(columns,leftFixedColumns,rightFixedColumns,record,index)}</tr>))}</tbody></table></div></div>);};functionclassNames(...names:(string|undefined)[]){constcurrentNames:string[]=[];names.forEach((name:(string|undefined))=>{if(name)currentNames.push(name);});returncurrentNames.join('');}functiongetFixedColumns(columns:ColumnType[]){consttotal:number=columns.length;constleftFixedColumns:number[]=[];constrightFixedColumns:number[]=[];if(columns[0].fixed){for(leti=0;i<total;i){if(columns[i].fixed){leftFixedColumns.push(i);}else{break;}}}if(columns[total-1].fixed){for(leti=total-1;i>=0;i--){if(columns[i].fixed){if(!leftFixedColumns.includes(i))rightFixedColumns.push(i);}else{break;}}}return[leftFixedColumns,rightFixedColumns];}functionrenderCols(columns:ColumnType[]){returncolumns.map((column:ColumnType,index:number)=>{constwidth:number=column.width||50;return(<colkey={index}style={{width:width,minWidth:width}}/>);});}functionrenderCells(columns:ColumnType[],leftFixedColumns:number[],rightFixedColumns:number[],record:any,index:number){returncolumns.map((column:ColumnType,index:number)=>{constalign:any=column.align||undefined;constfixed:string=leftFixedColumns.includes(index)?'left':(rightFixedColumns.includes(index)?'right':'');constclassName:string=classNames('st-table-cell',column.className,fixed?('st-table-cell-fix-'fixed):'');constrawValue:any=(column.dataKey&&column.dataKeyinrecord)?record[column.dataKey]:undefined;letvalue:any=undefined;if(column.render){value=column.render(rawValue,record,index);}else{value=(rawValue===undefined||rawValue===null)?'':String(rawValue);}return(<tdkey={index}className={className}style={{textAlign:align}}>{value}</td>);});}exportdefaultScrollableTable;components/ScrollableTable/index.less.st-table-container{border:1pxsolid#f0f0f0;border-right:0;border-bottom:0;font-size:14px;.st-table-header{border-right:1pxsolid#f0f0f0;overflow:hidden;table{border-collapse:separate;border-spacing:0;table-layout:fixed;width:100%;thead.st-table-thead{tr{th.st-table-cell{background:#fafafa;border-bottom:1pxsolid#f0f0f0;border-right:1pxsolid#f0f0f0;color:rgba(0,0,0,.85);font-weight:500;padding:8px;text-align:left;&:last-child{border-right:0;}}}}}}.st-table-body{overflow:autoscroll;border-bottom:1pxsolid#f0f0f0;border-right:1pxsolid#f0f0f0;table{border-collapse:separate;border-spacing:0;table-layout:fixed;tbody.st-table-tbody{tr.st-table-row{td.st-table-cell{border-bottom:1pxsolid#f0f0f0;border-right:1pxsolid#f0f0f0;color:rgba(0,0,0,.65);padding:8px;text-align:left;&:last-child{border-right:0;}}&:last-child{td.st-table-cell{border-bottom:0;}}}}}}table{.st-table-cell{&.st-table-cell-fix-left{background:#fff;position:sticky;left:0;z-index:2;}&.st-table-cell-fix-right{background:#fff;position:sticky;right:0;z-index:2;}}}}

然后可以这样使用:

views/Test/index.tsximportReact,{FunctionComponent}from'react';importPagefrom'../../components/Page';importScrollableTablefrom'../../components/ScrollableTable';importStoreProviderfrom'../../stores/products/context';import'./index.less';constTest:FunctionComponent<any>=(props:any)=>{letrecords:any[]=[{id:1,productName:'淡泰',amount1:198,amount2:200,amount3:205.5,currency:'人民币',ca:'Amy'},{productName:'方润',amount1:105.5,amount2:100,amount3:108,currency:'港元',ca:'Baby'},{productName:'医疗基金-1',amount1:153,amount2:150,amount3:155,currency:'人民币',ca:'Emily'},{productName:'医疗基金-2',amount1:302,amount2:300,amount3:290,currency:'美元',ca:'Baby'},{productName:'医疗基金-3',amount1:108.8,amount2:100,amount3:130,currency:'人民币',ca:'Amy'},{productName:'医疗基金-4',amount1:205,amount2:200,amount3:208,currency:'美元',ca:'吴丹'},{productName:'医疗基金-5',amount1:315.5,amount2:300,amount3:280,currency:'人民币',ca:'Baby'},{productName:'医疗基金-6',amount1:109,amount2:95,amount3:106,currency:'人民币',ca:'Emily'},{productName:'恒大私募债',amount1:213,amount2:200,amount3:208,currency:'港元',ca:'吴丹'}];consttotalRecord:any={productName:'合计',amount1:{},amount2:{},amount3:{}};records.forEach((record:any)=>{constcurrency:string=record.currency;['amount1','amount2','amount3'].forEach((key:string)=>{constvalue:any=totalRecord[key];if(!(currencyinvalue))value[currency]=0;value[currency]=record[key];});});records.push(totalRecord);constcolumns:any[]=[{dataKey:'productName',title:'产品名称',width:90,fixed:true},{dataKey:'amount1',title:<React.Fragment>上周缴款金额<br/>(万)</React.Fragment>,width:140,align:'center',className:'amount',render:calculateTotal},{dataKey:'amount2',title:<React.Fragment>上周预约金额<br/>(万)</React.Fragment>,width:140,align:'center',className:'amount',render:calculateTotal},{dataKey:'amount3',title:<React.Fragment>待本周跟进金额<br/>(万)</React.Fragment>,width:140,align:'center',className:'amount',render:calculateTotal},{dataKey:'currency',title:'币种',width:80},{dataKey:'ca',title:'CA',width:80}];return(<StoreProvider><Page{...props}title="销售统计"className="test"><divstyle={{padding:15}}><ScrollableTablewidth={window.innerWidth-30}height={196}columns={columns}dataSource={records}/></div></Page></StoreProvider>);};functioncalculateTotal(value:any){if(valueinstanceofObject){constkeys:any[]=Object.keys(value);return(<React.Fragment>{keys.map((key:string,index:number)=>(<spankey={index}>{`${value[key].toFixed(2)}万${key}`}</span>))}</React.Fragment>)}returnvalue.toFixed(2);}exportdefaultTest;views/Test/index.less.st-table-container{.st-table-body{td.st-table-cell.amount{padding-right:20px!important;text-align:right!important;span{display:block;}}}}

发表评论

  • 评论列表
还没有人评论,快来抢沙发吧~