首先说一下,
antd
封装的table
组件已经很方便了,为什么还要封装table
呢?在我们做项目时肯定不是一个人,而是一个团队,每个人都有自己的风格,总不能每次都在项目中或者去antd
官网拷贝一个table
吧,有些公共的部分,比如分页,时间久了,很难保证拷贝的一样如果没有特殊要求,一个系统能保持一致最好。
下面我就我在项目中使用table
的经验总结了此篇文章,我顺便也加入了动态列,方便以后自己拿来即用,如果能帮助到其他人那真的是再好不过了(本代码基于antd V5
)。
先看一下效果图:
先说一下封装思路,对于一个table
来说可分为表头、数据、分页,对于边框、每页显示多少条、总数、跳转这些功能都是很少改变的,所以最好把这些封装到组件中,如果哪一天突然想改变了,是不是只需要把组件改一下,是不是整个系统都改了,同时还支持外面传入,支持个别页面定制化。
demo目录结构如下:
组件的封装
src\components\table\index.js
- 通过
pagination
控制是否显示分页,三个参数current
、pageSize
、total
; resProps
是除去columns
、dataSource
、pagination
、columnsKey
这四个props
后的其他传入的props
参数;columnsKey
是控制右上角是否显示自动列功能,同时还是在localStorage
存储自动列的key
,存储的是columns
中的dataIndex
值,所以columns
中的dataIndex
不能重复;- 进入页面后,监听
columns
的变化,先去localStorage
中取值,如果有值就筛选出columns
,如果没值就直接用columns
。
// index.js
import React, { useEffect, useState } from 'react'
import { Table } from 'antd'
import AntdTableOptPage from './AntdTableOpt'
const AntdTablePage = props => {
// columnsKey,独一无二的表示,不能重复
const { columns, dataSource, pagination, columnsKey, ...resProps } = props
const [tableColumns, setTableColumns] = useState(columns || [])
useEffect(() => {
initFun()
}, [columns])
const initFun = () => {
let localColumns = columnsKey && localStorage.getItem(columnsKey)
if (localColumns) {
try {
let localColumnsJson = JSON.parse(localColumns)
// 设置table列
initTableColumns(localColumnsJson)
} catch (error) {
// 设置table列
initTableColumns([], 'init')
}
} else {
// 设置table列
initTableColumns([], 'init')
}
}
// 设置table列
const initTableColumns = (ls, type) => {
let newCol = []
for (let index = 0; index < columns.length; index++) {
const element = columns[index]
if (!element.dataIndex) {
newCol.push(element)
} else {
if (type === 'init') {
newCol.push(element)
} else {
if (ls.includes(element.dataIndex)) {
newCol.push(element)
}
}
}
}
if (!type) {
// 存储table列
columnsKey && localStorage.setItem(columnsKey, JSON.stringify(ls))
}
// 设置table列
setTableColumns(newCol)
}
return (
<div>
{columnsKey && (
<AntdTableOptPage
columnsChange={newColumns => {
initTableColumns(newColumns)
}}
tableColumns={tableColumns}
columns={columns.filter(itemMap => itemMap.dataIndex)}
/>
)}
<Table
size="small"
dataSource={dataSource.map((data, index) => {
return { ...data, key: index }
})}
bordered
columns={tableColumns}
pagination={
pagination
? {
current: pagination.current,
pageSize: pagination.pageSize,
total: pagination.total,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: [10, 20, 50, 100],
showTotal: total => `total ${total}`
}
: false
}
{...resProps}
/>
</div>
)
}
export default AntdTablePage
src\components\table\AntdTableOpt.js
// AntdTableOpt.js
import React, { useEffect, useState } from 'react'
import { Popover, Checkbox } from 'antd'
import { SettingOutlined } from '@ant-design/icons'
const AntdTableOptPage = props => {
const { columns, tableColumns, columnsChange } = props
// 操作后的columns
const defaultV = tableColumns
.map(itemMap => {
return itemMap.dataIndex
})
.filter(Boolean)
// 原始columns
const allDataIndex = columns
.map(item => {
return item.dataIndex
})
.filter(Boolean)
const [checkAll, setCheckAll] = useState(true)
useEffect(() => {
let defCheckAll = defaultV.length === allDataIndex.length ? true : false
setCheckAll(defCheckAll)
}, [tableColumns])
const content = (
<div>
<Checkbox.Group
style={{
width: '100%',
display: 'block',
maxHeightheight: '300px',
overflow: 'auto'
}}
value={defaultV}
onChange={value => {
columnsChange && columnsChange(value)
}}
>
{columns.map((item, idx) => {
return (
<div
style={{
padding: '5px 10px'
}}
key={idx}
>
<Checkbox value={item.dataIndex}>{item.title}</Checkbox>
</div>
)
})}
</Checkbox.Group>
</div>
)
const onCheckAllChange = () => {
let checkA = !checkAll
let dtIdxs = []
if (!checkAll) {
dtIdxs = allDataIndex
}
setCheckAll(checkA)
columnsChange && columnsChange(dtIdxs)
}
const contentSelAll = (
<div
style={{
padding: '5px 10px 10px',
borderBottom: '1px solid #ccc'
}}
>
<Checkbox
checked={checkAll}
onChange={() => {
onCheckAllChange()
}}
>
全选
</Checkbox>
</div>
)
return (
<div style={{
textAlign: 'right',
padding: '10px',
}}>
<Popover placement="leftBottom" content={content} title={contentSelAll} trigger="click">
<SettingOutlined />
</Popover>
</div>
)
}
export default AntdTableOptPage
src\App.js
import React, { useEffect, useState } from 'react'
import AntdTable from './components/table';
import './App.css';
const App = () => {
const paginationInit = {
current: 1,
pageSize: 10,
total: 0
}
const [queryFlag, setQueryFlag] = useState(false)
const [pagination, setPagination] = useState(paginationInit)
const [tableList, setTableList] = useState([])
useEffect(() => {
searchDataFun()
}, [queryFlag])
const tableColumns = [
{
title: 'Full Name',
dataIndex: 'name',
key: 'name'
},
{
title: 'Age',
dataIndex: 'age',
key: 'age'
},
{
title: 'Column 1',
dataIndex: 'address1',
key: '1',
},
{
title: 'Column 2',
dataIndex: 'address2',
key: '2',
},
{
title: 'Column 3',
dataIndex: 'address3',
key: '3',
},
{
title: 'Column 4',
dataIndex: 'address4',
key: '4',
},
{
title: 'Column 5',
dataIndex: 'address5',
key: '5',
},
{
title: 'Column 6',
dataIndex: 'address6',
key: '6',
},
{
title: 'Column 7',
dataIndex: 'address7',
key: '7',
},
{
title: 'Column 8',
dataIndex: 'address8',
key: '8',
}
]
const getData = () => {
let tableData = [];
let start = (pagination.current - 1) * pagination.pageSize
let end = (pagination.current) * pagination.pageSize
for (let i = start; i < end; i++) {
tableData.push({
key: i,
name: `Edward ${i}`,
age: 32,
address1: `London Park no. ${i}`,
address2: `London Park no. ${i}`,
address3: `London Park no. ${i}`,
address4: `London Park no. ${i}`,
address5: `London Park no. ${i}`,
address6: `London Park no. ${i}`,
address7: `London Park no. ${i}`,
address8: `London Park no. ${i}`,
});
}
return { records: tableData, total: 100 }
}
const searchDataFun = () => {
setTimeout(() => {
let res = getData()
setTableList(res.records)
const pg = {
...pagination,
total: res.total
}
setPagination(pg)
}, 500)
}
// const searchClearDataBtn = () => {
// const pg = {
// ...pagination,
// current: 1
// }
// setPagination(pg)
// setQueryFlag(!queryFlag)
// }
const handleTableChange = pagina => {
const params = {
...pagination,
current: pagina.current,
pageSize: pagina.pageSize
}
setPagination({ ...params })
setQueryFlag(!queryFlag)
}
return (
<div className="App">
<AntdTable
dataSource={tableList}
columns={tableColumns}
// 独一无二的表示,不能重复
columnsKey="tableLocalColumns"
pagination={pagination}
onChange={handleTableChange}
/>
</div>
);
}
export default App;