项目背景 : 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方法 , 添加自定义选择列
代码分为俩部分 , 一部分是父页面 , ( 父页面代码太多只显示了功能代码 )
特别注意 : 会出现第一行的拖拽失败 , 原因(当key是0时则不能拖拽 , 可以把data中的key赋值为id或者key+1 )
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 (
<Button
type='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}>
<SortableContext
items={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
} = props
const [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) => (
<Checkbox
checked={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'>
<SimpleBar
style={{ maxHeight: '600px', overflowY: 'auto', display: 'block' }}
className='SimpleBar'
>
<Table
components={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