用x-spreadsheet开发时需要用到导入导出功能,找了一堆只找到sheetJs的demo(https://docs.sheetjs.com/docs/demos/grid/xs
),在线体验(https://docs.sheetjs.com/xspreadsheet/
);
但是sheetJs要保留样式需要升级pro版本,所以用Excel.js 做了一个简单的实现,基本满足目前的需求, 原理是导入时把excel的数据格式转换成x-spreadsheet的数据格式,导出时在反过来转换。
因为搜到的其他人的文章给了我很大的帮助,所以用sheetJs的demo代码整理修改成这个单文件的示例,如果有人遇到同样的问题,希望能帮你节省一两个小时的时间
效果如图:
仓库地址:github.com/changgeee/x...
在线体验:changgeee.github.io/x-spreadshe...
主要代码:
scss
// 导入
let workbookData = [];
wb.eachSheet((sheet, sheetIndex) => {
// 构造x-data-spreadsheet 的 sheet 数据源结构
let sheetData = { name: sheet.name, styles: [], rows: {}, merges: [] }
// 收集合并单元格信息
let mergeAddressData = []
for (let mergeRange in sheet._merges) {
sheetData.merges.push(sheet._merges[mergeRange].shortRange)
let mergeAddress = {}
// 合并单元格起始地址
mergeAddress.startAddress = sheet._merges[mergeRange].tl
// 合并单元格终止地址
mergeAddress.endAddress = sheet._merges[mergeRange].br
// Y轴方向跨度
mergeAddress.YRange = sheet._merges[mergeRange].model.bottom - sheet._merges[mergeRange].model.top
// X轴方向跨度
mergeAddress.XRange = sheet._merges[mergeRange].model.right - sheet._merges[mergeRange].model.left
mergeAddressData.push(mergeAddress)
}
sheetData.cols = {}
for (let i = 0; i < sheet.columns.length; i++) {
sheetData.cols[i.toString()] = {}
if (sheet.columns[i].width) {
sheetData.cols[i.toString()].width = sheet.columns[i].width * 8
} else {
// 默认列宽
sheetData.cols[i.toString()].width = 100
}
}
// 遍历行
sheet.eachRow((row, rowIndex) => {
sheetData.rows[(rowIndex - 1).toString()] = { cells: {} }
if (row.height) {
sheetData.rows[(rowIndex - 1).toString()].height = row.height * 1.5;
}
row.eachCell({ includeEmpty: true }, function (cell, colNumber) {
let cellText = ''
if (cell.value && cell.value.result) {
// Excel 单元格有公式
cellText = cell.value.result
} else if (cell.value && cell.value.richText) {
// Excel 单元格是多行文本
for (let text in cell.value.richText) {
// 多行文本做累加
cellText += cell.value.richText[text].text
}
}
else {
// Excel 单元格无公式
cellText = cell.value
}
// 背景色
let backGroundColor = null
if (cell.style.fill && cell.style.fill.fgColor && cell.style.fill.fgColor.argb) {
backGroundColor = argb2hex(cell.style.fill.fgColor.argb)
}
if (backGroundColor) {
cell.style.bgcolor = backGroundColor
}
// 字体颜色
let fontColor = null
if (cell.style.font && cell.style.font.color && cell.style.font.color.argb) {
fontColor = argb2hex(cell.style.font.color.argb)
}
if (fontColor) {
//console.log(fontColor)
cell.style.color = fontColor
}
// 对齐
if (cell.style.alignment && cell.style.alignment.horizontal) {
cell.style.align = cell.style.alignment.horizontal
cell.style.valign = cell.style.alignment.vertical || "middle";
}
if (cell.style.border) {
// excel border
// {
// "left": {
// "style": "thin",
// "color": {
// "argb": "FF000000"
// }
// },
// "right": {
// "style": "thin",
// "color": {
// "argb": "FF000000"
// }
// },
// "top": {
// "style": "thin",
// "color": {
// "argb": "FF000000"
// }
// },
// "bottom": {
// "style": "thin",
// "color": {
// "argb": "FF000000"
// }
// }
// }
// xs border
// {
// "bottom": [
// "thin",
// "#000"
// ],
// "top": [
// "thin",
// "#000"
// ],
// "left": [
// "thin",
// "#000"
// ],
// "right": [
// "thin",
// "#000"
// ]
// }
const { left, right, top, bottom } = cell.style.border;
let bd = {
top: _.isArray(top) ? top : [top.style, argb2hex(top.color.argb)],
bottom: _.isArray(bottom) ? bottom : [bottom.style, argb2hex(bottom.color.argb)],
left: _.isArray(left) ? left : [left.style, argb2hex(left.color.argb)],
right: _.isArray(right) ? right : [right.style, argb2hex(right.color.argb)]
}
cell.style.border = bd;
}
//处理合并单元格
let mergeAddress = _.find(mergeAddressData, function (o) { return o.startAddress == cell._address })
if (mergeAddress) {
// 遍历的单元格属于合并单元格
if (cell.master.address != mergeAddress.startAddress) {
// 不是合并单元格中的第一个单元格不需要计入数据源
return
}
// 说明是合并单元格区域的起始单元格
sheetData.rows[(rowIndex - 1).toString()].cells[(colNumber - 1).toString()] = { text: cellText, style: 0, merge: [mergeAddress.YRange, mergeAddress.XRange] }
sheetData.styles.push(cell.style)
//对应的style存放序号
sheetData.rows[(rowIndex - 1).toString()].cells[(colNumber - 1).toString()].style = sheetData.styles.length - 1
}
else {
// 非合并单元格
sheetData.rows[(rowIndex - 1).toString()].cells[(colNumber - 1).toString()] = { text: cellText, style: 0 }
//解析单元格,包含样式
sheetData.styles.push(cell.style)
//对应的style存放序号
sheetData.rows[(rowIndex - 1).toString()].cells[(colNumber - 1).toString()].style = sheetData.styles.length - 1
}
});
})
workbookData.push(sheetData)
})
return workbookData;
这种方式只适合轻量化的web端表格编辑,如果需求复杂或者使用频率高,建议使用其他技术或商业库,如:
- SpreadJS(www.grapecity.com.cn/developer/s...
- SheetJS pro版本 (docs.sheetjs.com/docs/)
- Univer (docs.univer.ai/zh-CN/guide...
- onlyOffice (www.onlyoffice.com/)