js-xlsx + handsontable + echarts 实如今前端导入excel数据并生成echart报表javascript
最近都在作相似 ERP 的项目,因此呢,又碰到一个比较变态的需求(至少对我来讲是),在前端导入 excel 文件,
而后在浏览器里面预览和编辑, 最后再选择一些数据,用echarts生成报表.前端
js-xlsx 读取excel数据到jsvue
handsontable 相似Excel同样显示和编辑列表数据java
echarts 一个生成各类报表的库git
数据导入这边须要用到 浏览器的 FileReader对象
的 readAsBinaryString()
函数, 把选择的文件读取出来,
而后再监听 FileReader 对象的 onload 事件
, 在 onload 事件 的回调函数中,咱们能够获取到 读取的二进制数据.
这里顺便提一下, FileReader 对象提供如下方法,用来读取各类格式的数据(参考自MDN)github
FileReader.readAsArrayBuffer() // 读取文件的 ArrayBuffer 数据对象.apache
FileReader.readAsBinaryString() // 读取文件的原始二进制数据npm
FileReader.readAsDataURL() // 返回一个URL格式的字符串以表示所读取文件的内容json
FileReader.readAsText() // 返回一个字符串以表示所读取的文件内容数组
tips: 须要注意的是 readXxxxx() 函数,是不直接返回读取结果的,由于读取这个动做异步的.
readAsBinaryString 读取到的内容应该是一个二进制的字符串,这个时候,须要调用 js-xlsx
的 read
方法, read 返回的是一个可读性很强的对象了,我看了一下,里面有关于表格的属性不少都有
,如 样式, vsb宏, sheets等等 (反正我对excel也不熟,认识的也就这些哈),
npm i xlsx
import XLSX from 'xlsx' ... let res = XLSX.read(data, {type: 'binary'}) let sheetName = res.Sheets[res.SheetNames[0]] let table = XLSX.utils.sheet_to_json(sheetName, {header: 'A', raw: true, defval: ' '})
这里的 res 获得的我猜是 excel 表格原有的数据,里面包含上面说的不少种数据,而正常状况下,
咱们须要的每每只是第一个 sheet 里面的 纯数据
, 因此调用 XLSX.utils.sheet_to_json
获取第一个 sheet 的数据, table 拿到的应该是一个咱们熟悉的数组了.这个时候若是你只是单纯的渲染的话,
你甚至能够就此打住,本身写一个渲染方法(好比字符串拼接哈)把数据渲染出来便可.
若是单纯的显示没法知足你的需求,那么你可能须要 handsontable 了.
tips: sheet_to_json 的 第二个参数里面的 header,能够传数字,也能够转 'A', 两个的主要区别在于转化出来的表第一行若是是空行会不会正常显示,
传 'A' 会正常显示,传数字的话,若是表格的第一行有空白单元格,表格会错乱。
首先固然是安装,个人项目是基于 vue 的,因此要安装 vue 版本的,其余框架的,只要安装响应的版本便可.
npm i @handsontable/vue
而后就能够直接这么用
<template> <HotTable :settings="settings"></HotTable> </template> <script> import HotTable from '@handsontable/vue' export default { ... components: {HotTable} ... } </script>
模板里面的 settings 是 handsontable 的一些配置, 每一个项目的需求不一样,配置也不一样,这里就不列举出来了, 上面获取到的 table 在这里要赋值给 settings.data
我这里用 handsontable 显示数据的目的,是让用户能够清晰的看到上传的表的数据和结构,能够删除屌部分无用的数据,减小冗余。
数据都处理完了以后,就是生成报表了, 报表这里稍微作的灵活了一点,是要让用户根据上传的数据,本身选择字段,而后用 echart 去生成对应的报表。
为了偷懒下降复杂度,我这里只提供了3种报表类型供选择,分别是 饼图,柱状图,折线图,稍微分析 echart 的配置手册,我发现各类类型的图表,
其实主要的区别在 series 配置项下面,其余位置几乎没啥区别 就算有区别,也被我无视 。最终的实现大概是这样
let option = { title: {...}, tooltip: {...}, xAxis: {...}, yAxis: {...}, toolbox: {...}, } switch (type) { case 'pie' : option.series = {...} break case 'pie' : option.series = {...} break case 'pie' : option.series = {...} break } myChart.setOption(option)
echart 第一次渲染完之后,若是改变 option 的数据而后从新渲染,新的 option 数据是采用追加的方式加进去的,相似 javascript 的 Object.assign(),
因此若是新的数据没办法彻底覆盖掉就旧的数据的话,旧的那些没有被覆盖掉的数据,还会渲染出来. 我对这种状况的处理方法是调用dispose.dispose()
把实例销毁掉,
而后从新建立一个新实例,设置新的 option
源码记得star 和follow哦。