二次封装 ant-pro table + react-resizable实现表头控制拉拽

封装了 ant-pro table + react-resizable+form 可拖动表格。 拓展了一些功能,如格式化,支持保存用户表格宽度习惯,接口分页字段配置,可编辑表格等。

1 react-resizable 组件

import './index.less';
import { Resizable } from 'react-resizable';npm install --save react-resizable
npm install --save @types/react-resizable

2 类型声明文件源

import { useRef, useState, useEffect } from 'react';
import type {ListToolBarProps,ProColumns,ProTableProps,TableRowEditable,
} from '@ant-design/pro-table';
import { EditableProTable } from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import type { TablePaginationConfig } from 'antd';
import './index.less';
import { Resizable } from 'react-resizable';
import type { EditableProTableProps } from '@ant-design/pro-table/lib/components/EditableTable';
// import { cloneDeep } from 'lodash';
// import { getTableColumnsWidth, saveTableColumnsWidth } from '@/services/index';   // 用以保存用户使用表格宽度习惯

3 代码


/**** 注意* 拖动表格 columns render 中的div 要自己处理 div中的宽度不能写死* 设置宽度时要考虑拖拽图标的20px宽度* 如果需要动态表头并且需要拖拽 需要传key值 每次更新刷新列表 key值不能是随机数 否则每次render 都会被执行**/// 可拖动表格如果不需要拖拽 该列上添加属性isResizable=false  或者不设置dataIndex
type IProColumns = (ProColumns<any, any> & { isResizable?: boolean; titleName?: string })[];
interface UseTableProps {// 接口分页字段可能不统一  分页字段名paginationfield?: {page?: string;pageSize?: string;};// 其他的查询参数searchOtherParams?: any;// 设置x轴的滚动条 拖动属性为true有效scrollX?: number;// 接口名称api?: (params: any, params2?: any) => Promise<any>;// 是否拖动isResizable?: boolean;// 在fileProps中的属性会覆盖默认的属性fileProps?: {columns: IProColumns;} & ProTableProps<any, any>;// 会与默认分页拼接pagination?: false | TablePaginationConfig | undefined;// 会与默认工具栏拼接toolbar?: ListToolBarProps | undefined;// 编辑属性editable?: TableRowEditable<any>;// 编辑表格传入的属性editFileProps?: EditableProTableProps<any, any>;// 请求数据后转化的数据格式方法formatData?: (parasms: any) => any;tableName?: string; // 表格名称
}
// 拖拽方法
const ResizeableTitle = (resizeProps: { [x: string]: any; cresize: any; width: any }) => {const { cresize, width, isResizable, ...restProps } = resizeProps;delete restProps.cresize;if (!width) {return <th {...restProps} />;}// 如果 isResizable 为false 不添加拖拽if (isResizable === false) {return <th {...restProps} />;}return (<Resizablewidth={width}height={0}onResize={cresize}draggableOpts={{ enableUserSelectHack: false }}><th {...restProps} /></Resizable>);
};const MyProTable = (props: UseTableProps) => {// 判断当前页面的表格const [pathName] = useState<string>(location.pathname);const tableDom = useRef<HTMLDivElement>(null);const columnsWidthObj = useRef<Record<string, number | string>>({});const isDragegringRef = useRef<boolean>(false); // 是否正在拖动表头// 初始列const [defaultColumns, setDdefaultColumns] = useState<IProColumns>(props.fileProps?.columns || [],);// 滚动条 拖拽必需设置const [scrollX, setScrollX] = useState(0);// 覆盖默认的 table 元素const [components, setComponents] = useState<any>({cell: ResizeableTitle,});// 设置表头宽度为接接口返回的宽度const setColumnsWidth = (data: Record<string, string | number | undefined>) => {defaultColumns.forEach((item) => {if (typeof item.title === 'string') {if (data[item.title]) {item.width = data[item.title];}} else if (typeof item.titleName === 'string') {if (data[item.titleName]) {item.width = data[item.titleName];}}});setDdefaultColumns([...defaultColumns]);};useEffect(() => {if (props.isResizable) {setComponents({header: {cell: ResizeableTitle,},});}}, []);useEffect(() => {// 获取当前Table的所有THlet eles: any = null;const fn = (e: { stopPropagation: () => void }) => {e.stopPropagation();};setTimeout(() => {// location.pathname === pathName  是防止切换页面执行以下方法// 只有当前页面改变才会触发 切换页面会触发props.fileProps?.columns 依赖的useEffect 导致列的宽度不准确if (tableDom.current && location.pathname === pathName) {const theadThs = tableDom.current.getElementsByTagName('TH');// 记录隐藏列的个数    theadThs获取不到隐藏列的domlet count = 0;// 如果带复选框 不计算复选框的宽度if (props.fileProps?.rowSelection) {count -= 1;}// const columnsCopy = cloneDeep(props.fileProps?.columns);const columnsCopy = props.fileProps?.columns;// 获取当天所有TH的宽度总和 赋值给x轴的滚动条const total =columnsCopy?.reduce((num, item, index) => {if (item.hideInTable === true) {count += 1;return num;}// 修改默认列的宽度  (可能列设置了百分比或者没有设置宽度)if (theadThs[index - count]?.clientWidth) {Object.assign(item, {//  100 是防止报错width: theadThs[index - count]?.clientWidth + 0 || 100,});}// 如果没有dataIndex 给拖拽属性设置false 不添加拖拽功能if (!item.dataIndex) {Object.assign(item, {isResizable: false,});}return Number(item.width) + num;}, 0) || scrollX;// 表头宽度总和小于 传入的 scrollX 则用 计算宽度 否则用传入的 scrollXconst num = total < (props?.scrollX || 0) ? total : props?.scrollX || 0;setScrollX(num);if (props.fileProps) {setDdefaultColumns(columnsCopy as IProColumns);Object.assign(props.fileProps, {columns: columnsCopy,});}}// 查找所有拖拽图标添加阻止冒泡 (拖拽和排序会冲突)eles = document.querySelectorAll('.react-resizable-handle');if (eles && eles.length > 0) {eles.forEach((item: any) => {item.addEventListener('click', fn);});}}, 500);return () => {if (eles && eles.length > 0) {eles.forEach((item: any) => {item.removeEventListener('click', fn);});}};// 接口获取值更新columns后刷新 比如有数据字典的数据走接口 请求完成之前已经执行 导致请求后列上没有数据 所以添加依赖// 但是会导致切换页面也会执行 所以在上方通过路由判断只有当前页面触发才会执行}, [props.fileProps?.columns]);// 监听鼠标弹起useEffect(() => {// 获取表格宽度接口if (props.tableName) {// 获取用户使用表格宽度习惯// getTableColumnsWidth({ tableName: props.tableName }).then((res) => {//   try {//     const data = JSON.parse(res.data.headerLength);//     columnsWidthObj.current = data;//     setColumnsWidth(data);//   } catch (error) {//     console.error(error);//   }// });}const fn = () => {if (isDragegringRef.current && props.tableName) {setDdefaultColumns((columns) => {const obj: Record<string, any> = {};columns.forEach((item) => {if (typeof item.title === 'string') {obj[item.title] = item.width;} else if (typeof item.titleName === 'string') {obj[item.titleName] = item.width;} else {console.error('因为表头需要保存宽度,请在columns里面的加上title或者titleName为string类型',);}});// 保存表格宽度使用习惯// saveTableColumnsWidth({ tableName: props.tableName, headerLength: JSON.stringify(obj) });return columns;});isDragegringRef.current = false;}};window.addEventListener('mouseup', fn);return () => {window.removeEventListener('mouseup', fn);};}, []);// 查询数据const queryData = async (params: any) => {if (props.api) {const { pageSize, current } = params;// 接口的参数 页码和页数可能不统一delete params.current;delete params.pageSize;const res = await props.api({...params,[props.paginationfield?.pageSize || 'pageSize']: pageSize,[props.paginationfield?.page || 'page']: current,...props.searchOtherParams,});const data = props.formatData? props.formatData(res.data.records || res.data): res.data.records || res.data;return {data,success: res.code === 200,total: res.data.records ? res.data.total : res.data.length,};}return {data: [],success: false,total: 0,};};// 表格所有属性const tableAllProps: ProTableProps<any, any> = {rowKey: 'id',size: 'small',pagination: {pageSize: 10,...props.pagination,},toolbar: {...props.toolbar,},request: async (params = {}) => queryData(params),...props.fileProps,};// 拖动传true 会添加自定义表头和拖拽方法if (props.isResizable && defaultColumns) {const columns = defaultColumns.map((col, index) => ({...col,onHeaderCell: (): any => {return {width: col.width || 100,isResizable: col.isResizable,cresize: (_e: any, { size }: { size: any }) => {// console.log(11111);isDragegringRef.current = true;const nextColumns = [...columns];nextColumns[index] = {...nextColumns[index],width: size.width,};// console.log(nextColumns)const total = nextColumns.reduce((num, item) => {return Number(item.width) + num;}, 0);// 如果宽度总和小于传入的宽度 使用计算的宽度if (total < scrollX) {setScrollX(total);}setDdefaultColumns(nextColumns);},};},}));Object.assign(tableAllProps, {columns,});tableAllProps.scroll = props.fileProps?.scroll? { ...props.fileProps?.scroll, x: scrollX }: { x: scrollX };tableAllProps.components = components;tableAllProps.tableLayout = 'fixed';}const editFileProps: EditableProTableProps<any, any> = {rowKey: 'id',editable: {type: 'multiple',...props.editable,},...props.editFileProps,};return (<div ref={tableDom}>{props.editFileProps ? (<EditableProTable {...editFileProps} />) : (<ProTable {...tableAllProps} />)}</div>);
};// 设置组件默认props
MyProTable.defaultProps = { isResizable: true };export default MyProTable;

二次封装 ant-pro table + react-resizable实现表头控制拉拽相关推荐

  1. antd-vue table组件二次封装(ts版本)

    前言:现在公司开发大佬们都在用ant框架了,既然换框架,当然得重新二次封装组件,table又是最最常用的组件,所以打算记录一下目前在项目中用到的封装完成的table组件.非常方便,就算换项目,复制过去 ...

  2. antd picker 使用 如何_如何基于jsoneditor二次封装一个可实时预览的json编辑器组件?(react版)...

    前言 做为一名前端开发人员,掌握vue/react/angular等框架已经是必不可少的技能了,我们都知道,vue或react等MVVM框架提倡组件化开发,这样一方面可以提高组件复用性和可扩展性,另一 ...

  3. 看完这篇不要告诉我不会封装ant design弹框组件了

    我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣 获取前端学习知识 1设计需求 封装一个弹框组件 直接调用接口 2技术栈 ant design+react 设计第一步 绘制样式 < ...

  4. 数据列表组件 jqGrid 二次封装

    2019独角兽企业重金招聘Python工程师标准>>> 前段时间在jqgrid基础上,进行了二次封装. 应用在公司新的开发平台上,相比以前效果更佳,开发更方便,减少代码50%.共享下 ...

  5. 基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil

    基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil,把日常能用到的各种CRUD都进行了简化封装,让普通程序员只需关注业务即可,因为非常简单,故直接贴源代码,大家若需使用可以直 ...

  6. 二次封装dojo slider

    上次的二次封装timeslider,挺有意思,又来封装一个dojo的,样式还是用arcgis的. 实现更多功能,包括HorizontalSlider和VerticalSlider, 刻度的显示隐藏,标 ...

  7. eltable 无数据文案修改_el-table的二次封装详细版(一)

    最近一直在做公司的后台管理系统.就想着整理一些相关组件,方便自己方便他人. 我这里整理两个版本,都觉得挺好用.很常见,也是借鉴.然后整理后贴出来.代码我尽力贴全一些. 先发一个简单版的. {{ sco ...

  8. Echarts的二次封装思考心得。封装成果:折线柱状混合图、立体柱状折线混合图、markline标记线

    先说一下这次对ECharts二次封装总结的一些东西吧,感觉这是重点! 二次封装及使用的矛盾痛点: 一般封装只会暴露出一些常用的属性,最常见的如图表的颜色.数据: 封装人员也不会考虑把所有情况都封装起来 ...

  9. antd pro mysql_antd pro table中的文件上传

    概述 项目中经常会遇到在表格中展示图片的需求(比如展示用户信息时, 有一列是用户的头像). antd pro table 的功能很强大, 对于常规的信息展示只需参照示例配置 column 就可以了. ...

最新文章

  1. 人工智能+能源:能源行业变革新趋势
  2. VMware虚拟化--ESXi安装时考虑因素
  3. 如何获取shell脚本中某条语句的执行时间
  4. C++编程技巧—对数运算实现
  5. double类型进行比较排序
  6. 利刃 MVVMLight 2:Model、View、ViewModel结构以及全局视图模型注入器的说明
  7. Lc19删除链表的倒数第N个节点
  8. 系统科学专业 计算机,2018年北京市培养单位数学与系统科学研究院863计算机学科综合(专业)之计算机操作系统考研核心题库...
  9. 目前最快的 Java 框架居然是它?真的最快,秒射~
  10. android应用上架到各大应用市场总结
  11. (CVPR 2019) PointRCNN: 3D Object Proposal Generation and Detection From Point Cloud
  12. 软考-嵌入式系统设计师-笔记:历年专业英语题
  13. U8如何月结及反结账
  14. 计算机如何将两个磁盘合在一起,如何把两个磁盘合并在一起?
  15. wps“公式编辑器”的MT Extra 字体无效,将无法显示和打印某些字体。请重新安装“公式编辑器”,以便正确安装其字体
  16. 基于微信小程序的健康管理系统-计算机毕业设计
  17. 适合编程初学者的 入门级硬件: micro:bit
  18. 让C语言写图形库时不关闭控制台,GCC编译Win图形程序不显示控制台方法
  19. USB鼠标设备驱动程序简单实现(一)
  20. httpclient请求webservice接口

热门文章

  1. Debug版本下能运行而Release下不能运行的问题总结
  2. 本地sql文件怎样导入到服务器上,SQLServer怎样把本地数据导入到远程服务器上(转载)...
  3. 10万字最新Java热门面试题及答案总结
  4. IRS(intelligent reflecting surface)智能反射面与无人机通信
  5. 20221012 泊松公式
  6. 不讲战略的努力,都是扯淡!
  7. uevent 驱动_uevent分析(和设备驱动有关)
  8. ffmpeg转码,改变采样率
  9. 惠普HP LaserJet Pro 300 color MFP M375nw 驱动
  10. 视觉与激光雷达融合3D检测(一)AVOD