前言
之前做表格导出性能都是调用后端接口,由后端生成表格链接进行下载的,其实前端也是能够本人生成表格进行下载。
业务场景
在泛滥企业后盾治理中常常会遇到会须要导出页面统计类的表格或者输入打印类的图表,作为前端解决此类需要,我能想到的也就 2 中解决方向,一个是利用现有的表格类插件,二是利用 canvas 绘制图片导出。
目前好多企业都有大数据的需要,那未免对一些表格的数据须要进行解决。能够利用 xlsx/csv 进行解决。
csv 表格解决
表格解决最简略的就是 csv,对于页面中的 table 数据做转化解决就能够导出,有肯定的局限性,个性化能力较弱,个性化强的需要能够用 XLSX 插件解决。
导出 csv 表格解决
导出 csv 表格解决最次要的是处理单元格内的换行及字符编码问题解决。
let str = ``
let columns = [表格头部列数组]
let dataSource = [表格数据数组]
columns.forEach((element) => {str += `${ 表格头部列名},`
})
/**
* , 表格换行
* \r\n 单元格换行, 外层包裹双引号 ""
*/
dataSource.map((item) => {str +=`\r\n${ 行内容},"${单元格内容}\r\n${单元格内容}\r\n${单元格内容}"`
})
//encodeURIComponent 解决中文乱码
let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str)
let link = document.createElement('a')
link.href = uri
link.download = `${表格名称}.csv`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
canvas 图片解决
另外一种解决形式就是 canvas 解决,目前解决 canvas 最罕用的插件就是 html2canvas 了,在前端经常是封装成导图组件应用。
const imageWrapper = 须要绘制的 HTML 标签
const clientWidth = imageWrapper.offsetWidth
const clientHeight = imageWrapper.offsetHeight
const kh = [clientWidth, clientHeight]
html2canvas(imageWrapper, {
useCORS: true,
logging: true
}).then((canvas) => {const dataURL = canvas.toDataURL('image/png')
const getUrlBase64 = (url, kh) => {return new Promise((resolve) => {let canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const img = new Image()
img.crossOrigin = 'Anonymous' // 容许跨域
img.src = url
img.onload = () => {canvas.height = kh[1]
canvas.width = kh[0]
ctx.drawImage(img, 0, 0, kh[0], kh[1])
const dataURL = canvas.toDataURL('image/png')
canvas = null
resolve(dataURL)
}
})
}
getUrlBase64(dataURL, kh).then((base64) => {
// 下载
const link = document.createElement('a')
link.href = base64
link.download = `Loan Statement.png`
link.click()
// 新页面关上
let arr = base64.split(',') // 去掉 base64 格局图片的头部
let bstr = atob(arr[1]) //atob() 办法将数据解码
let leng = bstr.length
let u8arr = new Uint8Array(leng)
while (leng--) {u8arr[leng] = bstr.charCodeAt(leng) // 返回指定地位的字符的 Unicode 编码
}
window.open(window.URL.createObjectURL(new File([u8arr], `${图片名称}`, {type: 'image/png'})))
})
})
针对大数据表格解决类的需要
这类需要次要是针对大量表格须要对合乎正则的数据批量替换成大数据统计须要的一些标识。就须要辨认以后的表格内容,而后对数据进行解析再替换,最初导出,以下给出的是须要人为解决的的单个计划,感兴趣的能够集成为主动批量解决。利用的是 xlsx 插件解决导入的数据解析,及导出
const isUTF8(bytes)=> {
var i = 0
while (i < bytes.length) {
if (
// ASCII
bytes[i] == 0x09 ||
bytes[i] == 0x0a ||
bytes[i] == 0x0d ||
(0x20 <= bytes[i] && bytes[i] <= 0x7e)
) {
i += 1
continue
}
if (
// non-overlong 2-byte
0xc2 <= bytes[i] &&
bytes[i] <= 0xdf &&
0x80 <= bytes[i + 1] &&
bytes[i + 1] <= 0xbf
) {
i += 2
continue
}
if (
// excluding overlongs
(bytes[i] == 0xe0 && 0xa0 <= bytes[i + 1] && bytes[i + 1] <= 0xbf && 0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xbf) ||
// straight 3-byte
(((0xe1 <= bytes[i] && bytes[i] <= 0xec) || bytes[i] == 0xee || bytes[i] == 0xef) && 0x80 <= bytes[i + 1] && bytes[i + 1] <= 0xbf && 0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xbf) ||
// excluding surrogates
(bytes[i] == 0xed && 0x80 <= bytes[i + 1] && bytes[i + 1] <= 0x9f && 0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xbf)
) {
i += 3
continue
}
if (
// planes 1-3
(bytes[i] == 0xf0 &&
0x90 <= bytes[i + 1] &&
bytes[i + 1] <= 0xbf &&
0x80 <= bytes[i + 2] &&
bytes[i + 2] <= 0xbf &&
0x80 <= bytes[i + 3] &&
bytes[i + 3] <= 0xbf) || // planes 4-15
(0xf1 <= bytes[i] &&
bytes[i] <= 0xf3 &&
0x80 <= bytes[i + 1] &&
bytes[i + 1] <= 0xbf &&
0x80 <= bytes[i + 2] &&
bytes[i + 2] <= 0xbf &&
0x80 <= bytes[i + 3] &&
bytes[i + 3] <= 0xbf) || // plane 16
(bytes[i] == 0xf4 &&
0x80 <= bytes[i + 1] &&
bytes[i + 1] <= 0x8f &&
0x80 <= bytes[i + 2] &&
bytes[i + 2] <= 0xbf &&
0x80 <= bytes[i + 3] &&
bytes[i + 3] <= 0xbf)
) {
i += 4
continue
}
return false
}
return true
}
readFileType(file) {return new Promise((resolve, reject) => {const reader = new FileReader()
reader.onload = function (evt) {resolve(isUTF8(new Uint8Array(evt.target.result)))
}
reader.readAsArrayBuffer(file)
})
}
let reader = new FileReader()
let isCSV = file.name.split('.').pop().toLowerCase() === 'csv'
if (isCSV) {reader.readAsArrayBuffer(file)
const isUTF8 = await _this.readFileType(file)
isUTF8 ? reader.readAsText(file) : reader.readAsText(file, 'gbk')
} else {reader.readAsBinaryString(file)
}
reader.onload = function (e) {
let data = e.target.result
let workbook = XLSX.read(data, { type: 'binary'})
let sheetNames = workbook.SheetNames // 工作表名称汇合
let resultData = []
sheetNames.forEach((name) => {let worksheet = workbook.Sheets[name] // 只能通过工作表名称来获取指定工作表
resultData = XLSX.utils.sheet_to_json(worksheet, { header: 1})
})
// 再对 resultData 数据 json 进行转换成表格所需数据进行展现
}
// 导出 xlxs 表格
const data = 表格数据
let option = {} //option 代表的就是 excel 文件
let dataTable = [] //excel 文件中的数据内容
data.forEach((element) => {
element.author = this.XLSXAuthor
delete element.regExpMatch
})
let len = data.length
if (len) {for (let i = 0; i < len; i++) {let row = data[i]
let obj = {}
for (let key in row) {if (typeof row[key] === 'object') {let arr = row[key]
obj[key] = arr.map((item) => (typeof item === 'object' ? item.label : item)).join(',')
} else {obj[key] = row[key]
}
}
dataTable.push(obj) // 设置 excel 中每列所获取的数据源
}
}
let tableKeys = Object.keys(dataTable[0])
option.fileName = localStorage.getItem('XLSXFileName') //excel 文件名称
option.datas = [
{
sheetData: dataTable, //excel 文件中的数据源
sheetName: localStorage.getItem('XLSXFileName'), //excel 文件中 sheet 页名称
sheetFilter: tableKeys, //excel 文件中需显示的列数据
sheetHeader: tableKeys //excel 文件中每列的表头名称
}
]
let toExcel = new ExportJsonExcel(option) // 生成 excel 文件
toExcel.saveExcel() // 下载 excel 文件
这个案例是导入 xlsx/csv 表格,拿到表格数据再进行展现在页面,人为批改后再进行导出 xlsx,如果想再深刻一点,能够应用 node 编写一个转换表格数据的服务。这个就须要配合一些大数据的一些规定提取去实现。
结语
本次分享的都是在工作中遇到的表格的一些解决办法,集体的一些浅见,写的不好请轻喷!!!!欢送一起交换!!!!
前端表格解决知多少?