需求 : 在react中将表格多样化导出 , 既可以全部导出所有表格数据 , 也可以选择性导出 + 导出可以选择三种样式
选择了全部 , 不能选其他
全部导出
部分导出
1 导出按钮下拉弹出三种导出格式
<Dropdown
menu={{
items: [
{
label: (
<a
onClick={() => {
setFormat('xlsx')
}}
>
导出Excel
</a>
),
key: '1'
},
{
label: (
<a
onClick={() => {
setFormat('csv')
}}
>
导出CSV
</a>
),
key: '2'
},
{
label: (
<a
onClick={() => {
setFormat('txt')
}}
>
导出TXT
</a>
),
key: '3'
}
]
}}
>
<Button
type='primary'
ghost
icon={
<img
src={derive}
alt=''
style={{ width: 11, height: 10, pointerEvents: 'none' }}
/>
}
style={{ width: 125, height: 40, fontSize: 16 }}
>
导出
</Button>
</Dropdown>
2 多选框内选中全部时 , 其他不被选中 ; 选中其他时 , 全部不被选中
// Checkbox.Group不必被盒子包裹 , 而Radio.Group必须得被盒子包裹
<Checkbox.Group value={value2} onChange={value2Change}>
<Checkbox style={{ marginTop: 20, marginRight: 15 }} value={1}>
全部
</Checkbox>
<Checkbox
style={{ marginTop: 20, marginRight: 15 }}
value={'工单编号'}
>
工单编号
</Checkbox>
<Checkbox
style={{ marginTop: 20, marginRight: 15 }}
value={'地点'}
>
地点
</Checkbox>
<Checkbox
style={{ marginTop: 20, marginRight: 15 }}
value={'位置'}
>
位置
</Checkbox>
<Checkbox
style={{ marginTop: 20, marginRight: 15 }}
value={'设备类型'}
>
设备类型
</Checkbox>
<Checkbox
style={{ marginTop: 20, marginRight: 15 }}
value={'品牌/型号'}
>
品牌/型号
</Checkbox>
<Checkbox
style={{ marginTop: 20, marginRight: 15 }}
value={'设备编号'}
>
设备编号
</Checkbox>
<Checkbox
style={{ marginTop: 20, marginRight: 15 }}
value={'报修单状态'}
>
报修单状态
</Checkbox>
</Checkbox.Group>
const [value2, setValue2] = useState([1])
const value2Change = checkedValues => {
if (checkedValues.includes(1)) {
// 如果"全部"被选中,则清除所有其他选项,仅保留"全部"
if (checkedValues.length > 1) {
// 如果还有其他选项被选中,则清空数组,仅保留"全部"
setValue2([1])
} else {
// 如果只有"全部"被选中,保持现状
setValue2(checkedValues)
}
} else {
// 如果"全部"未被选中,且当前有其他选项被选中,则直接更新状态
// 注意:这里确保了当选择其他任何选项时,"全部"不会被选中
setValue2(checkedValues.filter(value => value !== 1))
}
}
// 拿到实时的value2
useEffect(() => {
console.log('value2', value2)
}, [value2])
3 导出的具体实现
3.1 data中定义了数据结构 , column是表格列的数据 , 我需要将data中列的数据转成column中title的值
流程图如下
const [data, setData] = useState([
{
key: '1',
username: 'B123',
realname: '北京总部大厦',
sex: '三层会议室',
birthday: '打印机',
phone: 'AB-0312',
orgCodeTxt: 'AB0312',
status: 1,
action: 1
},
...
]
const columns0 = [
{
title: <span onClick={() => handleSort('username')}>工单编号</span>,
dataIndex: 'username',
align: 'center',
key: 'username'
},
...
]
// 遍历columns0,为data中的每个对象创建一个仅含转换后数据的新对象
let data1 = data.map(item => {
const newItem = {}
columns0.forEach(column => {
const title = getTitleText(column)
const dataIndex = column.dataIndex
if (title && item.hasOwnProperty(dataIndex)) {
// 对于'status'列,直接应用状态码转换逻辑
newItem[title] =
column.dataIndex === 'status'
? getStatusText(item[dataIndex])
: item[dataIndex]
}
})
return newItem
})
console.log('data1', data1)
// 这样打印出data1的值 没有拿到想要的title 而是[object object]
3.2 遇到了[object object]的问题 , 没拿到想要的title值
原因 : column的title不是单纯的汉字 , 还被其他的img和span包裹着 , 导致没提取到正确的title
解决 : 根据typeof进行判断 , 是字符串直接返回 ; 或者.props && .props.children是字符串直接返回 ; 再或者就返回空
// 直接从columns配置中提取标题文本,忽略任何额外的JSX元素
function getTitleText (column) {
if (typeof column.title === 'string') {
return column.title
} else if (
column.title.props &&
typeof column.title.props.children === 'string'
) {
return column.title.props.children
}
return '' // 如果无法直接提取文本,则返回空字符串
}
// 提炼状态码转换逻辑为独立函数
function getStatusText (status) {
switch (status) {
case 1:
return '维修中'
case 2:
return '待派单'
case 3:
return '待确认'
case 4:
return '关单'
default:
return status.toString() // 或者其他默认处理
}
}
// 遍历columns0,为data中的每个对象创建一个仅含转换后数据的新对象
let data1 = data.map(item => {
const newItem = {}
columns0.forEach(column => {
const title = getTitleText(column)
const dataIndex = column.dataIndex
if (title && item.hasOwnProperty(dataIndex)) {
// 对于'status'列,直接应用状态码转换逻辑
newItem[title] =
column.dataIndex === 'status'
? getStatusText(item[dataIndex])
: item[dataIndex]
}
})
return newItem
})
console.log('data1', data1)
3.3 导出实现
import * as XLSX from 'xlsx'
import { saveAs } from 'file-saver'
const [format, setFormat] = useState('')
const handleDerive = columnsToExport => {
let dataSource = []
if (columnsToExport.includes(1)) {
dataSource = data1
} else {
dataSource = data1.map(row => {
const newRow = {}
columnsToExport.forEach(column => {
newRow[column] = row[column]
})
return newRow
})
}
const worksheet = XLSX.utils.json_to_sheet(dataSource)
const workbook = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
let fileExtension = ''
let mimeType = ''
console.log('format', format)
if (format === 'xlsx') {
setDeriveMoadal(true)
setFormat('xlsx')
// 导出为 Excel 文件
fileExtension = 'xlsx'
mimeType =
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
} else if (format === 'csv') {
// 导出为 CSV 文件
const csv = XLSX.utils.sheet_to_csv(worksheet)
const csvData = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
saveAs(csvData, 'export.csv')
return
} else if (format === 'txt') {
// 导出为 TXT 文件
const txt = XLSX.utils.sheet_to_txt(worksheet)
const txtData = new Blob([txt], { type: 'text/plain;charset=utf-8;' })
saveAs(txtData, 'export.txt')
return
}
const excelBuffer = XLSX.write(workbook, {
bookType: format,
type: 'array'
})
const excelBlob = new Blob([excelBuffer], { type: mimeType })
const url = window.URL.createObjectURL(excelBlob)
const link = document.createElement('a')
link.href = url
link.download = `export.${fileExtension}`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
}
}
useEffect(() => {
if (format) {
handleDerive()
}
}, [format])