美文网首页前端基础实用前端前端实际项目
纯前端利用 js-xlsx 实现 Excel 文件导入导出功能示

纯前端利用 js-xlsx 实现 Excel 文件导入导出功能示

作者: 关爱单身狗成长协会 | 来源:发表于2016-12-23 14:43 被阅读45288次

相关教程:
纯前端利用 js-xlsx 实现 Excel 文件导入导出功能示例(2)
纯前端利用 js-xlsx(3) 之合并单元格
纯前端利用 js-xlsx 之单元格样式(4)
js-xlsx导出自定义合并列头实现思路
js-xlsx工具类库 xlsxUtils 使用示例
handsontable结合js-xlsx实现可编辑xlsx导入导出功能(参考)
js-xlsx异步文件流读取示例

1.导入功能实现

下载js-xlsx到dist复制出xlsx.full.min.js引入到页面中
然后通过FileReader对象读取文件利用js-xlsx转成json数据
代码实现(==>示例<==)

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="http://oss.sheetjs.com/js-xlsx/xlsx.full.min.js"></script>
    </head>

    <body>
        <input type="file"onchange="importf(this)" />
        <div id="demo"></div>
        <script>
            /*
            FileReader共有4种读取方法:
            1.readAsArrayBuffer(file):将文件读取为ArrayBuffer。
            2.readAsBinaryString(file):将文件读取为二进制字符串
            3.readAsDataURL(file):将文件读取为Data URL
            4.readAsText(file, [encoding]):将文件读取为文本,encoding缺省值为'UTF-8'
                         */
            var wb;//读取完成的数据
            var rABS = false; //是否将文件读取为二进制字符串

            function importf(obj) {//导入
                if(!obj.files) {
                    return;
                }
                var f = obj.files[0];
                var reader = new FileReader();
                reader.onload = function(e) {
                    var data = e.target.result;
                    if(rABS) {
                        wb = XLSX.read(btoa(fixdata(data)), {//手动转化
                            type: 'base64'
                        });
                    } else {
                        wb = XLSX.read(data, {
                            type: 'binary'
                        });
                    }
                    //wb.SheetNames[0]是获取Sheets中第一个Sheet的名字
                    //wb.Sheets[Sheet名]获取第一个Sheet的数据
                    document.getElementById("demo").innerHTML= JSON.stringify( XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) );
                };
                if(rABS) {
                    reader.readAsArrayBuffer(f);
                } else {
                    reader.readAsBinaryString(f);
                }
            }

            function fixdata(data) { //文件流转BinaryString
                var o = "",
                    l = 0,
                    w = 10240;
                for(; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)));
                o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
                return o;
            }

        </script>
    </body>

</html>

2.导出功能的实现

同样引入js-xlsx
代码实现(==>示例<==)

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="http://oss.sheetjs.com/js-xlsx/xlsx.full.min.js"></script>
</head>

<body>
    <button onclick="downloadExl(jsono)">导出</button>
    <!--
            以下a标签不需要内容
        -->
    <a href="" download="这里是下载的文件名.xlsx" id="hf"></a>
    <script>
        var jsono = [{ //测试数据
            "保质期临期预警(天)": "adventLifecycle",
            "商品标题": "title",
            "建议零售价": "defaultPrice",
            "高(cm)": "height",
            "商品描述": "Description",
            "保质期禁售(天)": "lockupLifecycle",
            "商品名称": "skuName",
            "商品简介": "brief",
            "宽(cm)": "width",
            "阿达": "asdz",
            "货号": "goodsNo",
            "商品条码": "skuNo",
            "商品品牌": "brand",
            "净容积(cm^3)": "netVolume",
            "是否保质期管理": "isShelfLifeMgmt",
            "是否串号管理": "isSNMgmt",
            "商品颜色": "color",
            "尺码": "size",
            "是否批次管理": "isBatchMgmt",
            "商品编号": "skuCode",
            "商品简称": "shortName",
            "毛重(g)": "grossWeight",
            "长(cm)": "length",
            "英文名称": "englishName",
            "净重(g)": "netWeight",
            "商品分类": "categoryId",
            "这里超过了": 1111.0,
            "保质期(天)": "expDate"
        }];
        var tmpDown; //导出的二进制对象
        function downloadExl(json, type) {
            var tmpdata = json[0];
            json.unshift({});
            var keyMap = []; //获取keys
            //keyMap =Object.keys(json[0]);
            for (var k in tmpdata) {
                keyMap.push(k);
                json[0][k] = k;
            }
          var tmpdata = [];//用来保存转换好的json 
                json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
                    v: v[k],
                    position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
                }))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata[v.position] = {
                    v: v.v
                });
                var outputPos = Object.keys(tmpdata); //设置区域,比如表格从A1到D10
                var tmpWB = {
                    SheetNames: ['mySheet'], //保存的表标题
                    Sheets: {
                        'mySheet': Object.assign({},
                            tmpdata, //内容
                            {
                                '!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] //设置填充区域
                            })
                    }
                };
                tmpDown = new Blob([s2ab(XLSX.write(tmpWB, 
                    {bookType: (type == undefined ? 'xlsx':type),bookSST: false, type: 'binary'}//这里的数据是用来定义导出的格式类型
                    ))], {
                    type: ""
                }); //创建二进制对象写入转换好的字节流
            var href = URL.createObjectURL(tmpDown); //创建对象超链接
            document.getElementById("hf").href = href; //绑定a标签
            document.getElementById("hf").click(); //模拟点击实现下载
            setTimeout(function() { //延时释放
                URL.revokeObjectURL(tmpDown); //用URL.revokeObjectURL()来释放这个object URL
            }, 100);
        }

        function s2ab(s) { //字符串转字符流
            var buf = new ArrayBuffer(s.length);
            var view = new Uint8Array(buf);
            for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
            return buf;
        }
         // 将指定的自然数转换为26进制表示。映射关系:[0-25] -> [A-Z]。
        function getCharCol(n) {
            let temCol = '',
            s = '',
            m = 0
            while (n > 0) {
                m = n % 26 + 1
                s = String.fromCharCode(m + 64) + s
                n = (n - m) / 26
            }
            return s
        }
    </script>
</body>

</html>

3.使用Python将excel转成Json创建测试数据

代码

import sys
import xlrd
import json 
 
file =sys.argv[1] 
data = xlrd.open_workbook(file)
table=data.sheets()[0]

def haveNoIndex(table):
    returnData=[]
    keyMap=table.row_values(0) 
    for i in range(table.nrows):#row
        tmpmp={}
        tmpInd=0
        for k in table.row_values(i): 
            tmpmp[keyMap[tmpInd]]=k
            tmpInd=tmpInd+1  
        returnData.append(tmpmp);
    return json.dumps(returnData,ensure_ascii=False,indent=2)

returnJson= haveNoIndex(table) 
fp = open(file+".json","w",encoding='utf-8')
fp.write(returnJson)
fp.close()

导出示例的测试数据已经含有表头了如果没有表头可以直接将json中的遍历第一条数据的key创建一个value=key({key:key})插入到json第一条就可以了
其他相关教程参考:
Node读写Excel文件探究实践
XCel 项目总结 - Electron 与 Vue 的性能优化

相关文章

网友评论

  • 4maz1nG:你好,你这个测试数据键名是中文,我自己的是英文的,我用了elementUI,怎么才能让导出的表头显示为el-table-column的label属性值,label属性值是中文的
    关爱单身狗成长协会:@4maz1nG 你看看改成我下面那两个示例绑定方式看看 如果是获取写进去的值 那就通过 dom操作获取到列头数组 然后处理成json 再进行导出操作 吧
    4maz1nG:@关爱单身狗成长协会 我看了参考文章,是针对key本身是中文的,我这个是像你上面举的例子那<el-table-column label="数量" prop="amount">,这种情况的怎么处理
    关爱单身狗成长协会:如果是 导入导出 想要翻转 对象键值 参考函数 https://gitee.com/baojuhua/lutils/blob/master/src/json/reverse.js
    至于说 elementUI 导出标题显示的话
    那要看你在绑定 el-table-column 的中文是通过写死的方式 `<el-table-column label="数量" `
    还是通过 v-for `<el-table-column v-for="i in table.columns" :label="i.label" :prop="i.field"`
    还是 `<el-table-column v-for="(val, key, index) in table.columns" :label="table.columns[key]" :prop="key"` 不同绑定方式 所用方法不一样 你可以参考 文章 https://www.jianshu.com/p/c41730e48c31 进行导出操作
  • 138debc89b14:第一点击导入会有后台的报错信息。第二次选择同样的Excel表格,没有任何反应,前台debugger也进不来。如果第二次选择其他的Excel表格,就能正常导入。为什么呀!!!大神,能否给点建议
  • 394433c1aaa6:有没有整个项目😂大佬,刚入
    关爱单身狗成长协会:去 https://github.com/SheetJS/js-xlsx/tree/master/demos 转转
  • 兵兵_d89a:json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
    v: v[k],
    position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
    }))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata[v.position] = {
    v: v.v
    });

    这段代码能写成es5的语法吗?es6ie中不支持。
    关爱单身狗成长协会:分享个工具 https://babeljs.io/repl/
  • 404http:导出功能确定可以?我直接把上面的导出代码复制粘贴试了下,把导出的文件跟正规的excel表格文件同时用文本格式打开,正规的excel打开看到是乱码的,而导出的文件打开能看到一些html这些格式,说明明显不是真正的excel格式吧
    a657264d7c9e:excel在中间做的转换过程你不用关心吧..
    关爱单身狗成长协会:确定是html 不是 xml?
  • ssstone_cl:其实我想问,兼容性是不是基本都支持
    关爱单身狗成长协会:IE算是基本嘛:joy:
    ssstone_cl:有没有用在生产环境的例子,虽然很想用,准备先写个组件放公司测一下
  • 66b7f45defd5:您好, 请问一下可以导出chart 图表到Excel 中吗, 数据是动态的,
    66b7f45defd5:@关爱单身狗成长协会 :grin: ,谢谢
    关爱单身狗成长协会::sweat_smile: 没在官网找到相关方法
  • 7181526a4631:想知道为什么导入转为json的时候,为什么缺少excel表中第一行数据呢?
    夏不见秋:导入案例中,如果表头对应字段的值是空的,再转成json的时候那个字段直接是没有,这个怎么感觉不和谐呢?有另外的方法吗?
    关爱单身狗成长协会:@AmberJ512 嗯嗯 :blush: 可以结合文章开头其他链接教程作为参考
    7181526a4631:我知道为什么了 因为我的第一行就是数据,没有表头信息描述,会把第一行当作key-value中的key
  • 2cfa212fb1de:你好,请问node使用xlsx如何实现?
  • 35e8f5421981:你好,请问sheet_to_html将excel转为html时能否将表格的样式也能够读出来展示
  • 35e8f5421981:你好,我遇到一个很棘手的问题,因为这个xlsx.full.min.js里有几个require(),比如require("fs"),require("cptable"),我把这个js放在我们的项目就会去识别加载这几个js,所以系统就报错说找不到,请问大神这个该怎么解决呢,我是不是要把所有相关的js就放进去,因为我们的项目也是基于nodejs,加载js也是用的require()的方式
    关爱单身狗成长协会:@35e8f5421981 jar包是怎么回事:joy:
    35e8f5421981:@关爱单身狗成长协会 那如何结合到自己的项目中呢,对于这个我还是不太明白,应该把哪些jar包放在项目里
    关爱单身狗成长协会:官网 https://github.com/SheetJS/js-xlsx 上说用 npm install xlsx
  • _月光临海:已收藏,灰常感谢
  • 菠菜女皇:为什么在ie11下面“document.getElementById("hf").click(); //模拟点击实现下载”会报错呢,是被拒绝访问的,该如何解决呢
    关爱单身狗成长协会:楼上的回答不行试一下
  • 路灯下de男孩:这个导入功能兼容ie吗?
    关爱单身狗成长协会:@路灯下de男孩 :blush:
    路灯下de男孩:@关爱单身狗成长协会 我根据官网弄了一个兼容ie的,具体兼容到几没看,只有代码在我 jianshu:smile:
    关爱单身狗成长协会:额......插件的话 根据官网 https://github.com/SheetJS/js-xlsx 是支持ie6的 但是我写的的代码的话 可能是不兼容的 如果导入功能有问题 可以参考 18楼 的回答
  • 末小北先生:博主,看了你的文章,受益匪浅,xlsx导入是可以,但是xls导入就出错了,找了好多地方都没能很好的解决 ,博主或者广大简友可否解惑:blush:
    关爱单身狗成长协会:我上面放了示例了呀 你没看到吗?? http://runjs.cn/detail/p1bvlpjt
  • 活在初音的未来:使用中发现一个转换中遇到的问题,因为我是调取EXCEL的文件然后提交给后台(因为后台不想做这个导入功能),所以我提取的是JSON格式数据,但如果直接使用:
    ----------
    wb = XLSX.read(data, {
    type: 'binary'
    });
    let json = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
    ----------
    的话,得到的JSON数据中每个key值后面都会多个空格,如:{“name “:“Miku”}(为了明显我多敲了几个。
    所以如果需要JSON格式数据的话,需要进行处理:
    ----------
    let str = JSON.stringify(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
    // 转化为字符串,去除其中的空格
    let cont = JSON.parse(str.replace(/\s+/g,""))
    that._dataDeal(cont)
    ----------
    以上
    夏不见秋:@关爱单身狗成长协会 我测试了也不会有,但是如果字段对应的值是空,所对应的json字段直接没有,这个很是困惑
    关爱单身狗成长协会::hushed: 我测试了好像不会有呀! 不过还是谢谢分享解决方案
  • 活在初音的未来:十分感谢,官方文档没有写的很清晰,对于一些只用到简单导入导出功能的程序员来说,这个文章真的是十分有用,直接复制粘贴,配合代码微调格式,完美运行。
    感谢作者的贡献(来自单身狗的感谢
  • lijibing:导入功能 如果excel有多个工作表(sheet)页面的话只会读取第一个工作表的,官方例子是可以读取所有工作表的内容的,能否帮忙看一下
    关爱单身狗成长协会:@lijibing 其实就是EXCEL的单元格格式的设置问题 大多数默认情况下js解析出来的json对应值是 字符串或数字 所以无法对应到之前设置的格式 简单的解决办法你可以尝试在单元格格式选择自定义 然后像时间这种 可以输入自定义的格式 进行保存
    lijibing:@关爱单身狗成长协会 非常感谢楼主的回复,还想请教一下楼主。有些情况下excel中的日期,例如2017/12/15会被解析成12/15/17,有些情况不会发生。这应该还和EXCEL的格式设置有关,我在EXCEL中把解析成2017/12/15的数据复制到解析成12/15/17中的数据后也能正确解析成2017/12/15这种了。这种有办法解决吗
    关爱单身狗成长协会:上面代码中 有`... XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])...`
    wb.SheetNames是sheet名 示例代码默认取了索引第0个的名称 所以只取了一个
  • 付出的前端路:楼主,上面两个demo的源码求分享
  • 8a406322657b:大佬.......导入成功了,但是wb里面数据好乱了,有没有办法把excel数据直接整理成list
    关爱单身狗成长协会:@呐喊_395d 你导入完成后不是应该先过滤数据 然后在提交的吗???:flushed: (类似:http://www.jianshu.com/p/6cea596fb08f<;===这篇文章代码中的 showData函数)对数据整理后提交应该不会乱了吧
    8a406322657b:@关爱单身狗成长协会 但是那个List太复杂了,无法直接传到后台保存,我想生成类似form提交之后那样的数组list,跟name一一对应,不知道有没有办法
    关爱单身狗成长协会:代码里的 XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) 不就是吗?
  • c205f5ebacf2:这个方法兼容IE吗?我copy下来在IE上面没效果,chrome是可以的
    关爱单身狗成长协会:你说的是导入 还是导出,导入的话 ie11 我测试过是因为 没有 readAsArrayBuffer 方法,所以你可以使用base64 读取或参考 https://stackoverflow.com/questions/31391207/javascript-readasbinarystring-function-on-e11 ,如果导出的话可能是在 模拟点击下载的时候 需要将element插入到网页中 才有效。可以尝试 引用官方示例中的 <script src="http://sheetjs.com/demos/Blob.js";></script>
    <script src="http://sheetjs.com/demos/FileSaver.js";></script> 调用函数saveAs(blob,"文件名") 进行下载
  • 1c247d8cebc9:非常感谢楼主的分享,感激!
  • 大熊就是我:页面的table标签里的数据怎么导出啊
    大熊就是我:@关爱单身狗成长协会 好的...感谢...我研究下
    关爱单身狗成长协会:一种方法 通过将table 用js转成json 然后
    另一种 通过 JS-XLSX自带方法 查看示例(右键查看源码)http://sheetjs.com/demos/modify.html
  • 62b6ce7ff387:第一次添加xlsx文件时能正确读取,相同的文件再次导入时不触发,会不会是缓存没有清掉,或者因为文件相同的原因change没有触发?如何解决!
    关爱单身狗成长协会:读取完成后将 input 的 value 值 设置成空字符串就可以了
  • 7ce04b8ffc65:你好,导出的时候我想改变他们的表格位置 不想就两行显示 我想让他像个列表那样去显示 要怎么搞呢 这个demo有api吗?
    关爱单身狗成长协会:不明白你要的效果,你可以吧你的效果xlsx文件通过网盘共享出来。查看demo的话 前往===> http://sheetjs.com/demos/
  • 62f9e185d6d6:你好,我是个小白,我想问一下,为什么第二个导出功能我写完后没用?
    关爱单身狗成长协会:@Aureole_7b57 :frowning: 你浏览器是什么版本的呀
    62f9e185d6d6:@关爱单身狗成长协会 Uncaught SyntaxError: missing ) after argument list json.map((v, i) => keyMap.map((k, j) =>……所在的行
    关爱单身狗成长协会:能告诉我 控制台报什么错吗:joy:
  • 茳茳:如何设置,单元格宽度哦。内容产出内容单元格宽度
    茳茳:@关爱单身狗成长协会 :joy:
    关爱单身狗成长协会::joy: 我没搞过! 官网有教程 好像是 这个:https://github.com/SheetJS/js-xlsx#column-properties
  • 三文鱼的一生:请教下 ,你知道xlsxjs 怎么操作excel里面的图片文件吗
    关爱单身狗成长协会:说真的,我建议不要入"图片坑",对图片操作挺繁琐的,因为 图片包含 单元格图片 背景图片 字符图片 等等,要录入的图片信息有比如说:大小,定位,边框,等样式,而且图片本身格式有很多,即使要弄我也不介意在前端处理。
    给你几个参考资料吧:https://github.com/xSirrioNx/js-xlsx
    https://github.com/SheetJS/js-xlsx/issues/128
    https://github.com/SheetJS/js-xlsx/pull/509
  • 疯狂的向日葵:你好,这个框架能设置Excel单元格样式 、合并单元格什么的吗?
    关爱单身狗成长协会:可以的。官网教程 非常详细, 合并单元格可以参考文章 http://www.jianshu.com/p/5c131c27841c
  • wshger:貌似只是支持XLSX / XLSM,把类型写成XLS 导出excel里面什么都没有了
    wshger:@一个不正经的dotnet程序员 谢谢
    关爱单身狗成长协会:格式支持很多但,导出xlsx时比较兼容中文 。想要导出其他格式 查看文章 http://www.jianshu.com/p/044c183edf42
    wshger:我是这么写的 <button onclick="downloadExl(jsono,'biff2')">导出</button>
    <a href="" download="这里是下载的文件名.xls" id="hf"></a>
  • 70bdabf91cc0: 你好!我想问一下在导出的时候,为何打开导出的excel时候会出现一个弹框,上面写着‘发现excel部分内容存在问题,是否让我们尝试修复。。。。。’,我点是以后,就可以打开了,也能成功导出,请问这个弹框的出现是什么原因导致的,谢谢你的回答!
    关爱单身狗成长协会:@一个不正经的dotnet程序员 [补充]参考里面的 showData 函数的想法
    关爱单身狗成长协会:@70bdabf91cc0 对于导出显示直接不想显示的数据值的时候 简易自己根据自己定义的规则在导出钱进行数据 清洗替换 你 可以查看我的 http://www.jianshu.com/p/6cea596fb08f 这篇文章 导入时对数据 清洗替换 的操作
    70bdabf91cc0:自己回答一下自己提的问题,后台返回的json键值对中,value还有null,所以我推测还有一写保留字符不能出现,但是可以以字符串的形式出现,例如‘null’,'undefined'
  • 581046c3f53b:为什么第一次导出 显示文件损坏啥的 第二次就有用了
    4f05a8f4704a:我试过感觉没问题,提高js操作Excel效率,兰兰~
    70bdabf91cc0:你好!我想问一下在导出的时候,为何打开导出的excel时候会出现一个弹框,上面写着‘发现excel部分内容存在问题,是否让我们尝试修复。。。。。’,我点是以后,就可以打开了,也能成功导出,请问这个弹框的出现是什么原因导致的,谢谢你的回答!
    关爱单身狗成长协会:上面的示例???
  • e41544bb65e4:大神为什么第二个导出excel的会报错,在 json.map((v, i) = > keyMap.map((k, j) = > Object.assign({}, {
    v: v[k],
    position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
    }))).reduce((prev, next) = > prev.concat(next)).forEach((v, i) = > tmpdata[v.position] = {
    v: v.v
    });
    这个地方会报错
    关爱单身狗成长协会:谢谢 提醒,我也发现问题了 原来是我用在线html格式化工具导致的
    :flushed:
  • 7c27f24e04d3:非常感谢你的分享,js-xlsx的文档太复杂了,你刚好把最常用的2个功能分享出来:+1:
  • 30a802846857:你好,导出的数据里怎么保留数字格式,现在导出来都是字符串的?
    关爱单身狗成长协会:@morow 导入 还是 导出呀???我导出来默认是字符串的呀 应该 不会变的
    30a802846857:@一个不正经的dotnet程序员 百分比的数导出来怎么让它还是显示百分数呢,现在好像都会变成小数:pray:
    关爱单身狗成长协会:默认好像的确全是字符串的。前往github:https://github.com/SheetJS/js-xlsx 里面说的比较比较详细。
  • 鱼缸太小:ajax如何使用呢?
    关爱单身狗成长协会:@景夏_917d 是这样吗?===> http://www.jianshu.com/p/8ce5b8e47e46
    鱼缸太小:@一个不正经的dotnet程序员 我的意思是如果要读取的文件是一个url地址。怎么来实现呢?
    关爱单身狗成长协会:额...=_= 并不是 很清楚你想表达的具体意思。如果是异步问题的话 可以使用回调或Promise 来进行异步控制

本文标题:纯前端利用 js-xlsx 实现 Excel 文件导入导出功能示

本文链接:https://www.haomeiwen.com/subject/aiekvttx.html