背景
关于这篇文章出的原因,这里说明一下,有个项目导表功能一直是前端用
xlsx
这个库去导的。有一天,运营人员过来反馈:"导出的表有瑕疵,当我双击文本11-3-9
去修改的时候,它老是把这个11-3-9
自动转成2011/3/9
,这个能不能规避这个问题"。
问题
gif图看看👀:
拢共就这个问题(全篇解决的就是这个问题,如果遇到同样问题可以看下去,没有的话,也可以看👀也可以不看🙈,我只是做个笔记📒)。后端接口返回的本就是字符串: "9-4-17"... 等等
剖析
当我们重新创建一个新的xlsx表格文件的时候,
科普 : wps、office 等表格软件中当用户输入1-2-3
双击或者是回车下,软件会自动将其解释为日期格式,并填充相应的日期。这种行为,是表格软件中具有一个内置的日期识别功能------"数字-数字-数字"
这样格式的文本,会自动识别它将其转换成日期格式。
这就解释了运营人员为什么导出表时,一旦双击修改或者触碰到这种"数字-数字-数字"
格式的文本会自动转成年/月/日
,但这不是他们想要的,他们目前想要的是所见即所得的"数字-数字-数字"
文本。
解决
(Excel)常用的自定义格式:
-
G/通用格式
: 设定为G/通用格式
的单元格,我们输入数字1、...、9 阿拉伯数字,它会自认定为数字,我们输入文字a、...、z,它会自认定为文字,输入1-2-3,或者1/2/3会自动转为日期。 -
@
:不管我们输入1、...、9或者a、...、z或者1-2-3,或者1/2/3,它一律认定为文字。
这里统计了单元格格式的自定义详解
,如有需要,可以去自取所用。
那么,以上去关于Excel的一些定义解释。
在前端,我们如何把表中的单元格设置为@
这种通用文本呢。
由于这个项目用了xlsx
的库去做的导表,以下就用xlsx
来举例:
javascript
function changeData (s) {
if (typeof ArrayBuffer !== 'undefined') {
buf = new ArrayBuffer(s.length)
const view = new Uint8Array(buf)
for (const i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
return buf
} else {
buf = new Array(s.length)
for (const j = 0; j !== s.length; ++j) buf[j] = s.charCodeAt(j) & 0xFF
return buf
}
}
javascript
import XLSX from 'xlsx'
import FileSaver from 'file-saver'
/**
type: '', // 不同的导出格式,比如: json_to_sheet、table_to_book
elementOrArray: '', // 如果是json_to_sheet就是array, 如果是table_to_book就是元素(这里不涉及table_to_book这种方式)
filename: '' // 文件名📃
**/
function exportExcel (type, elementOrArray, filename) {
switch (type) {
//... 有其它case
case 'json_to_sheet':
const wopts = {
bookType: 'xlsx',
bookSST: true,
type: 'binary'
}
let workBook = {
SheetNames: [],
Sheets: {},
Props: {}
}
// elementOrArray这里用array是一个表中有很多sheet的情况
elementOrArray.forEach(element => {
workBook.SheetNames.push(element.sheetName)
workBook.Sheets[element.sheetName] = XLSX.utils.json_to_sheet(element.sheetArray)
})
FileSaver.saveAs(
new Blob(
[changeData(XLSX.write(workBook, wopts))],
{ type: 'application/octet-stream' }
),
filename
)
break
}
}
✅ 这里的workBook.Sheets['表名']
就是这里文件每个单元格的总对象:
A1对象里面有 { t: 's', v: 'id' }
, t代表type
类型,s即是string, v代表value,每个值的文本。
那么如果要设置每个'1-1-1'这种格式的文本的单元格为通用文本
,忽略excel的自动转化日期。
只要在这个对象里添加 z: '@'
即可。
kotlin
for (const i in workBook.Sheets['表名']) {
const val = String(workBook.Sheets['表名'][i].v)
if (val && val.includes('-')) {
workBook.Sheets['表名'][i].z = '@'
}
}
如此一来,只要是这个单元格设置了 z: '@'
,就是告诉excel,这个单元格是文本占位符
。不用自动识别转化成日期。
也就是通用代码如下:
javascript
const XLSX = require('xlsx')
// 创建一个工作簿
const workbook = XLSX.readFile('文件路径', { cellStyles: true })
// 获得第一个sheet工作表
const worksheet = workbook.Sheets[workbook.SheetNames[0]]
// 设置A1单元格格式为文本
const cell = 'A1'
const style = { t: 's', z: '@' } // z: '@' 表示通用文本格式
worksheet[cell].s = style
// 之后就是导出
XLSX.writeFile(workbook, '存放的文件目录位置', { bookType: 'xlsx', cellStyles: true } )
原理:
把需要设置的单元格,循环去设置单元格格式样式,{ z: '@' } , 就能规避这种前端 XLSX导表避免1-2-3 这种字符串双击自动转日期,或者其他触发了excel自动单元格格式转化的机制。
☎️ 希望对大家有所帮助,如有错误,望不吝赐教,欢迎评论区留言互相学习。感谢阅读,祝您开发有乐趣。