项目背景 : react + ant
需求 : 点击表头设置弹窗 , 拖拽可控制外部表格列的排序 , 开关可控制外部表格列的显示和隐藏
实现效果如下 :
注意 : 1. 拖拽效果参考了ant-table中的拖拽效果(这块代码放最后)
2. 后台反了json格式(用is_show控制显示和隐藏 , 我给他传递sort值来控制排序 , 后台返回格式如下~)
3. 将拖拽和显示隐藏后的内容存到了localStorage
实现 :
const [biaotouData, setBiaotouData] = useState([
{
key: 'orderNumber',
orderNumber: '工单编号'
},
{
key: 'placeName',
orderNumber: '地点'
},
.....
])
const biaotouColumns = [
{
render: () => <DragHandle /> // 让拖拽图标在第一列
},
{
title: (
<span style={{ color: dropdownOpen1 ? ' var(--main-bg)' : '#333' }}>
{t('HeaderColumn')}
</span>
),
dataIndex: 'orderNumber',
align: 'center',
key: 'orderNumber'
},
{
title: (
<span style={{ color: dropdownOpen2 ? ' var(--main-bg)' : '#333' }}>
{t('WhetherDisplayed')}
</span>
),
align: 'center',
dataIndex: 'placeName',
key: 'placeName',
render: (data, record) => (
<div>
<Switch
checked={getIsShowForColumn(record.key)} // 使用getIsShowForColumn函数获取当前列的is_show状态
onChange={data => handleSwitchChange(record, data)}
/>
</div>
)
}
]
const sortedColumns = sortColumnsBySort(tableColumns) // 排序后的列,传递给外部的table
const [biaotouModal, setBiaotouModal] = useState(false) // 控制表头设置的显示隐藏
const [sortData, setSortData] = useState() //拿到表头列的显示状态
// 打开表头设置弹窗
const biaotouHandle = async () => {
setBiaotouModal(true)
const res = await getList7({ type: 3 })
console.log('res.titleSetContent', res.titleSetContent)
setSortData(JSON.parse(res.titleSetContent))
}
// 排序
function sortColumnsBySort (columns) {
return columns.sort((a, b) => a.sort - b.sort)
}
// 在渲染Switch的地方,查找当前列对应的is_show值
const getIsShowForColumn = columnName => {
return sortData?.find(item => item.name === columnName)?.is_show ?? true // 如果找不到,默认为true
}
// 当拖拽和显示和隐藏后外部表格更新
useEffect(() => {
if (sortData) {
const updateAndHandleResponse = async () => {
const res = await getEditMethod3({
titleSetContent: JSON.stringify(sortData),
type: 3
})
localStorage.setItem('hiddenColumns1', JSON.stringify(sortData))
const updatedColumns = tableColumns.map(column => {
if (
sortData.find(
item => item.name === column.key && item.is_show === false
)
) {
return { ...column, hidden: true }
} else if (
sortData.find(
item => item.name === column.key && item.is_show === true
)
) {
return { ...column, hidden: false }
}
return column
})
setTableColumns(updatedColumns)
}
updateAndHandleResponse()
}
}, [sortData, biaotouModal])
// 当拖拽和显示和隐藏后外部表格更新
useEffect(() => {
const storedHiddenColumns = localStorage.getItem('hiddenColumns1')
if (storedHiddenColumns) {
const hiddenColumns = JSON.parse(storedHiddenColumns)
const updatedTableColumns = tableColumns.map(column => {
if (
hiddenColumns.find(
item => item.name === column.key && item.is_show === false
)
) {
return { ...column, hidden: true }
} else if (
hiddenColumns.find(
item => item.name === column.key && item.is_show === true
)
) {
return { ...column, hidden: false }
}
return column
})
setTableColumns(updatedTableColumns)
}
return () => {
}
}, [])
------------------------------------------------这是表头设置的table 和 外部的table 和 拖拽代码--------------
// 表头设置里的table
<DndContext
modifiers={[restrictToVerticalAxis]}
onDragEnd={onDragEnd}
>
<SortableContext
items={biaotouData.map(i => i?.key)}
strategy={verticalListSortingStrategy}
>
<SimpleBar
style={{
maxHeight: '600px',
overflowY: 'auto',
display: 'block'
}}
className='SimpleBar'
>
<Table
columns={biaotouColumns}
dataSource={biaotouData}
loading={loading}
pagination={false}
components={{
body: {
row: Row1
}
}}
rowKey='key'
></Table>
</SimpleBar>
</SortableContext>
</DndContext>
// 外部的table
{TableCom2({ loading, data, columns: sortedColumns })}
//被拖拽后
const onDragEnd = ({ active, over }) => {
console.log('active', active)
if (active.id !== over?.id) {
setBiaotouData(biaotouData => {
const activeIndex = biaotouData.findIndex(
item => item?.key === active.id
)
const overIndex = biaotouData.findIndex(item => item?.key === over?.id)
const newData = arrayMove(biaotouData, activeIndex, overIndex).map(
(item, index) => ({
...item,
sort: index + 1
})
)
// 创建一个新的映射以方便查找
const keyToSortMap = newData.reduce((map, item) => {
map[item.key] = item.sort
return map
}, {})
console.log('keyToSortMap', keyToSortMap)
// 遍历sortData,根据name查找对应的新Data中的sort值并赋值
sortData.forEach(item => {
if (item.name in keyToSortMap) {
item.sort = keyToSortMap[item.name]
}
})
// 遍历sortData,根据name查找对应的新Data中的sort值并赋值
tableColumns.forEach(item => {
if (item.key in keyToSortMap) {
item.sort = keyToSortMap[item.key]
}
})
setTableColumns(tableColumns)
localStorage.setItem('hiddenColumns1', JSON.stringify(sortData))
console.log('Updated sortData:', sortData)
console.log('sortData', sortData)
console.log('newData', newData)
console.log('tableColumns', tableColumns)
getEditMethod3({
titleSetContent: JSON.stringify(sortData),
type: 3
})
return arrayMove(biaotouData, activeIndex, overIndex)
})
}
}
//控制是否可以选中表格里的文字
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}
/>
)
}