在现代Web应用中,处理Excel文件是一个常见的需求。用户希望能够在浏览器中展示Excel文件的内容,并能够对部分内容进行编辑,最后将修改后的文件保存回服务器。为了实现这一需求,我们可以使用 SheetJS
和 Handsontable
这两个强大的库。本文将详细介绍如何实现这一功能,并探讨在处理公式时的难点与解决方案。
1. 依赖库的选择与安装
首先,我们需要安装 SheetJS
和 Handsontable
这两个库。SheetJS
用于读取和写入Excel文件,而 Handsontable
则提供了一个类似于Excel的表格编辑器。
bash
npm install xlsx handsontable @handsontable/vue3
对于一些特定的需求,比如公式的实时计算,可能需要使用 SheetJS
的付费版本。不过,本文我们将重点介绍如何在不依赖付费功能的情况下,实现基本的Excel文件展示与编辑。
2. 从服务器读取Excel文件
我们从服务器获取Excel文件流,并将其解析为可用于前端展示的数据格式。以下是获取文件流并解析的代码示例:
javascript
const fileArrayBuffer = ref()
const fileLoading = ref(false)
const getExcelFileData = async () => {
fileLoading.value = true
const res = await getExcelReq(参数)
fileLoading.value = false
fileArrayBuffer.value = res
}
const parseExcel = (arrayBuffer) => {
const workbook = XLSX.read(arrayBuffer, { type: 'array', cellFormula: true })
const firstSheetName = workbook.SheetNames[0]
const worksheet = workbook.Sheets[firstSheetName]
const data = XLSX.utils.sheet_to_json(worksheet, {
header: 1,
defval: '',
raw: false,
formula: true,
})
dataSource.value = data
// 提取公式
const formulas = {}
const range = XLSX.utils.decode_range(worksheet['!ref'])
for (let R = range.s.r; R <= range.e.r; ++R) {
for (let C = range.s.c; C <= range.e.c; ++C) {
const cellAddress = XLSX.utils.encode_cell({ r: R, c: C })
const cell = worksheet[cellAddress]
if (cell && cell.f) {
formulas[cellAddress] = cell.f
}
}
}
// 提取合并单元格信息
const merges = worksheet['!merges'] || []
// 提取冻结区域信息
const freeze = {
rows: worksheet['!freeze']?.rows || 0,
cols: worksheet['!freeze']?.cols || 0,
}
return { data, formulas, merges, freeze }
}
在这段代码中,我们首先通过 XLSX.read
读取文件流,然后提取工作表、数据、公式、合并单元格和冻结区域等信息。这些信息将用于后续的表格展示与编辑。
3. 使用Handsontable展示与编辑表格
接下来,我们使用 Handsontable
来展示从Excel文件中提取的数据,并允许用户进行编辑。以下是初始化 Handsontable
的代码:
javascript
const initHandsontable = (container, parsedData) => {
if (hotInstance.value) {
hotInstance.value.destroy()
hotInstance.value = null
}
const { data, formulas, merges, freeze } = parsedData
hotSettings.value = {
data: data,
rowHeaders: true,
colHeaders: true,
contextMenu: true,
manualRowResize: true,
manualColumnResize: true,
mergeCells: merges.map((merge) => ({
row: merge.s.r,
col: merge.s.c,
rowspan: merge.e.r - merge.s.r + 1,
colspan: merge.e.c - merge.s.c + 1,
})),
fixedRowsTop: freeze.rows,
fixedColumnsLeft: freeze.cols,
formulas: formulas,
licenseKey: 'non-commercial-and-evaluation',
cells: (row, col, prop) => {
const cellAddress = XLSX.utils.encode_cell({ r: row, c: col })
if (formulas[cellAddress]) {
return { readOnly: true }
}
return {}
},
}
hotInstance.value = new Handsontable(container, hotSettings.value)
}
在这段代码中,我们配置了 Handsontable
的各种选项,包括数据、合并单元格、冻结区域、以及公式的处理。对于包含公式的单元格,我们将其设置为只读,以防止用户修改公式。
4. 保存编辑后的Excel文件
用户完成编辑后,我们可以将修改后的数据保存回服务器。以下是保存文件的代码:
javascript
const handleSettleSave = async () => {
if (!hotInstance.value) return
const updatedData = hotInstance.value.getData()
const worksheet = XLSX.utils.aoa_to_sheet(updatedData)
const workbook = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' })
const blob = new Blob([excelBuffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
})
const formData = new FormData()
formData.append('file', blob, 'updated_file.xlsx')
try {
loading.value = true
const response = await saveSettleFileReq(formData)
if (response.code == 200 || response.data) {
Message.success('文件保存成功')
}
loading.value = false
} catch (error) {
console.error('文件上传失败:', error)
}
}
在这段代码中,我们将修改后的数据转换成Excel文件,并将文件流上传到服务器。
5. 公式处理的挑战
在使用 SheetJS
时,公式的实时计算是一个较为复杂的问题。SheetJS
的免费版本虽然可以读取公式,但不支持实时计算和更新。如果您的应用需要实时计算功能,可能需要使用 SheetJS
的付费版本,或者考虑其他支持公式计算的库。
6. 总结
通过 SheetJS
和 Handsontable
,我们可以轻松地在Web应用中实现Excel文件的前端展示与编辑。尽管在处理公式时存在一些挑战,但对于大多数基础需求来说,这套方案已经足够强大且易于实现。
希望这篇文章能帮助你在项目中更好地处理Excel文件。如果你有任何问题或建议,欢迎在评论区留言讨论!