项目背景 : react + ant
要实现 : 有多选功能(实现批量删除 , 也可以全选) + 可以拖拽(可以复制 , 方便顶部的搜索功能)
要实现效果如下
1 这是最初的拖拽功能实现 , 不能复制表格里的内容 , 不符合要求
2 更改了ROW的内容 , 实现了可以复制表格内容
代码
//控制是否可以选中表格里的文字
const Row1 = props => {const {attributes,listeners,setNodeRef,setActivatorNodeRef,transform,transition,isDragging} = useSortable({id: props['data-row-key']})const style = {...props.style,transform: CSS.Translate.toString(transform),transition,...(isDragging? {position: 'relative',zIndex: 9999}: {})}const contextValue = useMemo(() => ({setActivatorNodeRef,listeners}),[setActivatorNodeRef, listeners])return (<RowContext.Provider value={contextValue}><tr {...props} ref={setNodeRef} style={style} {...attributes} /></RowContext.Provider>)
}
3 多选功能ant官网也只提供了rowSelection方法 , 而rowSelection的位置总是在表格最左边 , 我需要让拖拽icon在最左边 , 多选功能在icon右边 , 目前问题如下
解决思路 : 舍弃了官网的rowSelection方法 , 添加自定义选择列
代码分为俩部分 , 一部分是父页面 , ( 父页面代码太多只显示了功能代码 )
import React, { useContext, useMemo, useState, useEffect } from 'react'
import { HolderOutlined } from '@ant-design/icons'
import { DndContext } from '@dnd-kit/core'
import { restrictToVerticalAxis } from '@dnd-kit/modifiers'
import {arrayMove,SortableContext,useSortable,verticalListSortingStrategy
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
const RowContext = React.createContext({})//控制是否可以选中表格里的文字
const Row1 = props => {const {attributes,listeners,setNodeRef,setActivatorNodeRef,transform,transition,isDragging} = useSortable({id: props['data-row-key']})const style = {...props.style,transform: CSS.Translate.toString(transform),transition,...(isDragging? {position: 'relative',zIndex: 9999}: {})}const contextValue = useMemo(() => ({setActivatorNodeRef,listeners}),[setActivatorNodeRef, listeners])return (<RowContext.Provider value={contextValue}><tr {...props} ref={setNodeRef} style={style} {...attributes} /></RowContext.Provider>)
}//拖拽图标
const DragHandle = () => {const { setActivatorNodeRef, listeners } = useContext(RowContext)return (<Buttontype='text'size='small'icon={<HolderOutlined />}style={{cursor: 'move'}}ref={setActivatorNodeRef}{...listeners}/>)
}function role () {//被拖拽后请求接口和数据改变const onDragEnd = ({ active, over }) => {if (active.id !== over?.id) {setData(data => {const activeIndex = data.findIndex(item => item?.key === active.id)const overIndex = data.findIndex(item => item?.key === over?.id)const newData = arrayMove(data, activeIndex, overIndex).map((item, index) => ({...item,sort: data.length - index}))// 收集newData中所有对象的id和sort值const updatedItems = newData.map(item => ({id: item.roleId,sort: item.sort}))getSortMethod({ sorts: updatedItems }) //后端接口return arrayMove(data, activeIndex, overIndex)})}}// 让拖拽icon在左侧const columns = [{width: 60,render: () => <DragHandle />},...]return (<><DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}><SortableContextitems={data.map(i => i?.key)}strategy={verticalListSortingStrategy}>{TableComSelect1({loading,data,columns,onSelectionChange: handleSelectionChange, // 选中的表格数量信息传递给表格isSelectAll: isSelectAll, //是否全选rowKey: 'key', //拖拽components: { //拖拽body: {row: Row1}}})}</SortableContext></DndContext></>)
}export default role
另一部分是封装的表格组件 ( 全部代码如下 )
import React, { useState, useEffect, useContext } from 'react'
import { Table, Button, Checkbox } from 'antd'import SimpleBar from 'simplebar-react'import 'simplebar/dist/simplebar.min.css' // 引入 simplebar 的样式
import './index.less'
import { useTranslation } from 'react-i18next' // 引入 useTranslation 钩子
import i18n from '@/utils/i18n' //国际化组件const TableComSelect1 = props => {const { t } = useTranslation() // 获取翻译函数和语言切换函数const [obj, setObj] = useState({})const {components,rowKey,columns = [],data = [],loading = false,onSelectionChange,isSelectAll} = propsconst [selectedRowKeys, setSelectedRowKeys] = useState([]) //让批量删除后不被选中const [selectionType, setSelectionType] = useState('checkbox')//接收父传递的key 用来控制表格选中const onSelectChange = newSelectedRowKeys => {console.log('selectedRowKeys changed: ', newSelectedRowKeys)setSelectedRowKeys(newSelectedRowKeys) //让子表格可以选中onSelectionChange(newSelectedRowKeys) //将选中的子表格选中的key值赋给父组件}//旧的选择功能,一直在最左侧const rowSelection = {selectedRowKeys,onChange: onSelectChange}// 点击全选useEffect(() => {if (isSelectAll) {setSelectedRowKeys(data.map(item => item.key))} else {setSelectedRowKeys([])}}, [isSelectAll])// 创建一个自定义的选择列const selectionColumn = {width: '100px',title: t('select'), // 或者根据需要设置标题fixed: 'left', // 如果需要固定列,请保留此行render: (_, record) => (<Checkboxchecked={selectedRowKeys.includes(record[rowKey])} // 假设rowKey是用于唯一标识记录的字段onChange={() => {const newSelectedRowKeys = [...selectedRowKeys]if (newSelectedRowKeys.includes(record[rowKey])) {newSelectedRowKeys.splice(newSelectedRowKeys.indexOf(record[rowKey]),1)} else {newSelectedRowKeys.push(record[rowKey])}setSelectedRowKeys(newSelectedRowKeys)onSelectionChange(newSelectedRowKeys) // 更新父组件的选中项}}/>)}// 在columns数组的第二位插入自定义的选择列const updatedColumns = [...columns.slice(0, 1), // 取前一列selectionColumn, // 插入选择列...columns.slice(1) // 取剩余列]return (<div className='TableComSelect1'><SimpleBarstyle={{ maxHeight: '600px', overflowY: 'auto', display: 'block' }}className='SimpleBar'><Tablecomponents={components} // 应用自定义行组件等rowKey={rowKey} // 设置行键columns={updatedColumns}dataSource={data}loading={loading}pagination={false}// rowSelection={{ //旧的选择功能会一直在表格最左边// ...rowSelection,// type: selectionType,// columnTitle: t('select'),// columnWidth: '100px'// }}scroll={{x: 1700}}></Table></SimpleBar></div>)
}
export default TableComSelect1