一、前言
目标
在ant design
的Table
组件基础之上利用react-dnd
实现表格列的拖拽排序、并自定义列的显示隐藏。
Tips
- 请先了解
ant design
组件库中Table
组件的用法,本文不再展开 - 本文不展开介绍
react-dnd
的基础知识,不太了解它的同学可以先参考文末的文章学习
当前版本
react
:16.14.0
react-dom
:16.14.0
antd
:3.26.20
react-dnd
:11.1.3
react-dnd-html5-backend
:11.1.3
二、实现代码
为自定义的表格组件取名CustomColumnTable
拖拽方案说明
- 在组件之外还得用
DndProvider
包裹,否则无法使用拖拽功能 - 拖拽实现方案是拖拽表头列实现整列位置替换
- 表头列既可以被拖拽也可以接受被拖拽的列
- 缺陷:无法有效过滤 表格行可选择(rowSelection)时的选择列 和 固定列(fixed)
传入参数说明
这里是分了两种情况:
当外部组件传入的columns
数组不会发生变化
- 此时
dynamicColumns
为false,意味着之后表格列的拖拽排序与显示隐藏全由封装的CustomColumnTable
组件来控制
当columns
数组会发生变化时
- 比如在不同场景下,显示的表格列名不同,展示方式不同,这时外部组件传入的
columns
可能会发生变化,无法完全交由CustomColumnTable
组件控制。此时外部组件传入columns
时可以为每个子项添加selected
属性,表示CustomColumnTable
组件是否能控制该列的显示隐藏和拖拽 - 同时外部组件需传递
dynamicColumns
onChangeColumn
两个参数,且onChangeColumn
函数的参数是已处理好的新columns数组,外部组件拿到后可以用来替换原columns数组
区分selected
和visible
selected
表示CustomColumnTable
组件是否能控制该列显示隐藏和拖拽位置,默认为true
,false
表示CustomColumnTable
组件暂时无法控制它visible
表示列是否显示,这由完全CustomColumnTable
组件来控制,true
显示,false
隐藏selected
的优先级比visible
高,在列的selected
属性为false
下,无论visible
属性是否为true
,表格都不会显示该列
import React, {
useState, useRef } from 'react';
import {
Button, Checkbox, Popover, Table } from 'antd';
import {
createDndContext, DndProvider, useDrag, useDrop } from 'react-dnd';
import {
HTML5Backend } from 'react-dnd-html5-backend';
const type = 'DragTableHeadCol';
const DNDContext = createDndContext(HTML5Backend);
const swapArray = (arr, index1, index2) => {
const dragCol = arr[index1];
arr.splice(index1, 1);
arr.splice(index2, 0, dragCol);
return arr;
};
/**
* @param index 表头列的位置下标
* @param moveCol 拖拽结束时排序方法
*/
const dragdrop = (index, moveCol) => {
const ref = React.useRef();
const [, drop] = useDrop({
accept: type,
drop: item => {
// item.index表示被拖拽组件的下标
// index是接受被拖拽组件的下标
moveCol(item.index, index);
},
});
const [, drag] = useDrag({
item: {
type, index },
});
// 让组件既可以被拖拽也可以接受被拖拽组件
drop(drag(ref));
return {
ref };
};
// 对tableHeadRow进行封装
const DragTableHeadRow = ({
children, moveCol }) => {
// 对列进行处理,使其可拖拽
const Ths = children.map((th, index) => {
const {
props: {
className, style, children: thChildren },
} = th;
const {