使用纯JavaScript如何实现Excel IO
沉沙 2018-07-23 来源 : 阅读 1010 评论 0

摘要:本篇JavaScript教程探讨了使用纯JavaScript如何实现Excel IO,希望阅读本篇文章以后大家有所收获,帮助大家对JavaScript的理解更加深入。

具体要求包含

· Excel导入导出

· 根据导入的数据进行展示报表

· 图表展示(包括柱状图,折线图,饼图),而且还要求要有动画效果,扁平化风格

· Excel导出,并要提供客户端来管理Excel 文件

· …

 

在整个项目架构中,首先就要解决Excel导入的问题。

嗯,我在github上找到了一个开源库xlsx,通过npm方式来安装。

npm install xlsx --save

   

之后,在自己的html文件里面添加对js文件的引用

<script src="./node_modules/xlsx/dist/jszip.js"></script>

<script src="./node_modules/xlsx/dist/xlsx.js"></script>

   

通过FileReader对象将数据以二进制字符串的方式加载到内存中,

target.addEventListener('drop', function (e) {

  e.preventDefault();

  handleDrop(e.dataTransfer.files[0]);

});

handleDrop = function(){

  var reader = new FileReader();

  reader.onload = function (e) {

    var data = e.target.result;

    ...

    ...

  };

  reader.readAsBinaryString(f);

}

   

然后我们下来的操作就是要利用库对data数据进行操作了。

它暴露了一个对象XLSX,通过XLSX的read() 方法就可以将数据读为JSON对象了。

var workbook = XLSX.read(data, { type: 'binary' });

var sheetName = workbook.SheetNames[0];

var sheet = workbook.Sheets[sheetName];

   

之后,使用键值对的方式再把数据从sheet中取出来放到表格中。

var table = document.createElement('table');

for (var row = 1; ; row++) {

    if (sheet['A' + row] == null) {

        break;

    }

    var tr = document.createElement('tr');

 

    for (var col = 65; col <= 90; col++) {

        var c = String.fromCharCode(col);// get 'A', 'B', 'C' ...

        var key = '' + c + row;

        if (sheet[key] == null) {

            break;

        }

        var td = document.createElement('td');

        td.innerHTML = sheet[key]['w'];

        tr.appendChild(td);

    }

    table.appendChild(tr);

}

document.querySelector('#target').appendChild(table);

   

下面是完整代码:

index.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Document</title>

    <style>

        #target {

            height: 400px;

            width: 700px;

            background-color: #f8f8f8;

            margin: 200px auto;

            overflow:hidden;

            border-radius:5px;

            box-shadow:2px 2px 5px #888;

        }    

        .hover::before {

            content: '请将excel文件拖到这里';

            width: 100%;

            height: 100%;

            display: block;

            text-align: center;

            line-height: 400px;

            font-size: 24px;

            font-family: '微软雅黑';

        }

        #target>table{

            height:250px;

            width:400px;

            border:1px solid #ccc;

            border-radius:3px;

            margin:75px auto;

        }

        #target>table td{

            text-align:center;

            border-top:1px solid #ccc;

            border-left:1px solid #ccc;

        }

         #target>table tr:first-child>td{

             border-top:0px solid #ccc;

         }

         #target>table tr>td:first-child{

             border-left:0px solid #ccc;

         }

    </style>

</head>

<body>

    <div id="target" class="hover">

    </div>

  

    <script src="./node_modules/xlsx/dist/jszip.js"></script>

    <script src="./node_modules/xlsx/dist/xlsx.js"></script>

    <script src="index.js"></script>

</body>

</html>

   

下面是完整js代码

index.js

window.addEventListener('load', function () {

    var target = document.querySelector('#target');

    target.addEventListener('dragenter', function () {

        this.classList.remove('hover');

    });

    target.addEventListener('dragleave', function () {

        this.classList.add('hover');

    });

    target.addEventListener('dragover', function (e) {

        this.classList.remove('hover');

        e.preventDefault();

    });

 

    target.addEventListener('drop', function (e) {

        e.preventDefault();

        handleDrop(e.dataTransfer.files[0]);

    });

 

});

var handleDrop = function (f) {

    var reader = new FileReader(),

        name = f.name;

    reader.onload = function (e) {

        var data = e.target.result,

            workbook = XLSX.read(data, { type: 'binary' }),

            sheetName = workbook.SheetNames[0],

            sheet = workbook.Sheets[sheetName],

            table = document.createElement('table');

      

        for (var row = 1; ; row++) {

            if (sheet['A' + row] == null) {

                break;

            }

            var tr = document.createElement('tr');

 

            for (var col = 65; col <= 90; col++) {

                var c = String.fromCharCode(col);// get 'A', 'B', 'C' ...

                var key = '' + c + row;

                if (sheet[key] == null) {

                    break;

                }

                var td = document.createElement('td');

                td.innerHTML = sheet[key]['w'];

                tr.appendChild(td);

            }

            table.appendChild(tr);

        }

        document.querySelector('#target').appendChild(table);

    };

    reader.readAsBinaryString(f);

}

   

效果如下:

 

这样做好像可行,但是我们很快就放弃了。

弊端太多了。

· 这个库现在目前还处于开发阶段,在issues里面还有很多的Bug被提出。这没有办法保证最终网站的稳定性。

· 这个库没有办法导入合并单元格的数据,只能是很死板的按照’A’, ‘B’, ‘C’… 和1, 2, 3 坐标来查询数据,而且它要求内部单元格不能为空。

· 更比较不方便的就是,它没有行和列的计数的属性。

· 由于这是为国企做的,所以无法将关键功能依赖于这个star量不是很多的库,降低风险,也是为了网站的安全性。

· …

 

经过小组探讨,我们决定使用另外一款前端控件,叫做 Wijmo。

首先,从网站上下载Wijmo包,这个控件没有提供npm和bower等方式。

 

然后将我需要的包导入进来

<script src="./wijmo/dist/controls/wijmo.min.js"></script>

<script src="./wijmo/dist/controls/wijmo.grid.min.js"></script>

<script src="./wijmo/dist/controls/wijmo.grid.detail.min.js"></script>

<script src="./wijmo/dist/controls/wijmo.grid.xlsx.min.js"></script>

<script src="./wijmo/dist/controls/wijmo.xlsx.min.js"></script>

   

此外,还有引入一个jszip的包,是使用js来解压压缩包的一个库。(由于MS的open xml技术,xlsx文件都可以解压成为xml文件,app.xml 里包含了主要的数据)。

<script src="./jszip.min.js"></script>

   

读取文件的操作和上面都是一样的

var handleDrop = function (file) {

    var reader,

        workbook;

  

    if (file) {

        reader = new FileReader;

        reader.onload = function (e) {

            workbook = new wijmo.xlsx.Workbook(),

                workbook.load(reader.result);

        };

        reader.readAsDataURL(file);

    }

}

   

通过

workbook = new wijmo.xlsx.Workbook();

workbook.load(reader.result);

   

这两行代码将excel文件加载到内存 中的workbook对象。

打印workbook对象,

 

打印这个对象发现,workbook里面包含sheets数组,每个sheet包含rows数组,每个row包含cells数组,每个cell里面vaule属性就是单元格的值。
这简直太又好了

下面实现一个函数 getCollectionView ,以对象数组的方式来获取数据

var getCollectionView = function (workbook) {

    var collectionView = [];

    if (workbook) {

        var sheet = workbook.sheets[0],

            header = []; // 列标题数组

      

        for (var i = 0, length = sheet.rows.length; i < length; i++) {

            var row = sheet.rows[i],

                rowArray = {};

            for (var j = 0, jLength = row.cells.length; j < jLength; j++) {

                var cell = row.cells[j];

                // 如果是第一行数据,那么是作为列标题出现的,就放进标题数组中

                if (i === 0) {

                    header.push(cell.value);

                }

                else {

                    // 后面的行数组,就作为rowArray对象的属性存储,属性名就是该列的标题。

                    rowArray[header[j]] = cell.value;

                }

            }

            if (i !== 0) {

                collectionView.push(rowArray);

            }

        }

    }

    return collectionView;

}

   

然后需要一个表格将数据呈现出来,这里我直接使用了Wijmo的FlexGrid表格。

gridDiv = document.createElement('div');

gridDiv.classList.add('grid');

dataGrid = new wijmo.grid.FlexGrid(gridDiv);// 通过传入容器构造一个FlexGrid表单。

var collectionView = new wijmo.collections.CollectionView(getCollectionView(workbook));

dataGrid.itemsSource = collectionView;

   

好了,经过上面几个步骤,导入Excel到表格已经实现了

这是完整的js代码:

index.js

(function () {

    var dataGrid = null,

        gridDiv = null,

        workbook = null;

    window.addEventListener('load', function () {

        gridDiv = document.createElement('div');

        gridDiv.classList.add('grid');

        dataGrid = new wijmo.grid.FlexGrid(gridDiv);

        var target = document.querySelector('#target');

 

        target.addEventListener('dragenter', function (e) {

            e.preventDefault();

            this.classList.remove('hover');

 

        });

        target.addEventListener('dragleave', function (e) {

            e.preventDefault();

            this.classList.add('hover');

        });

        target.addEventListener('dragover', function (e) {

            e.preventDefault();

            this.classList.remove('hover');

        });

 

        target.addEventListener('drop', function (e) {

            e.preventDefault();

            handleDrop(e.dataTransfer.files[0]);

            // 将这个表单添加到页面上

            this.appendChild(gridDiv);

        });

    });

 

    var handleDrop = function (file) {

        var reader;

        var workbook;

      

        if (file) {

            reader = new FileReader;

            reader.onload = function (e) {

                workbook = new wijmo.xlsx.Workbook();

                workbook.load(reader.result);

                var collectionView = new          wijmo.collections.CollectionView(getCollectionView(workbook));

                dataGrid.itemsSource = collectionView;

                // console.log(dataGrid.collectionView);

            };

            reader.readAsDataURL(file);

        }

    }

 

    var getCollectionView = function (workbook) {

        var collectionView = [];

      

        if (workbook) {

            var sheet = workbook.sheets[0];

            var title = [];

          

            for (var i = 0, length = sheet.rows.length; i < length; i++) {

                var row = sheet.rows[i];

                var rowArray = {};

              

                for (var j = 0, jLength = row.cells.length; j < jLength; j++) {

                    var cell = row.cells[j];

                    if (i === 0) {

                        header.push(cell.value);

                    }

                    else {

                        rowArray[header[j]] = cell.value;

                    }

                }

                if (i !== 0) {

                    collectionView.push(rowArray);

                }

            }

        }

        return collectionView;

    }

})(window);

   

下面是效果

 

Excel 导出

欧了

两句代码实现Excel导出功能

wijmo.grid.xlsx.FlexGridXlsxConverter.save(dataGrid,

    { includeColumnHeaders: true }, fileName);

   

这个表格还支持过滤,分组,筛选,编辑。

 

面积图和柱状图

就在完成Excel IO 之后,发现这个控件包还可以做面积图,柱状图和其他很多类型的图形。

所以在这里就演示一个面积图的和一个柱状图的例子。

首先,要将包引进来。

<script src="./wijmo/dist/controls/wijmo.chart.min.js"></script>

   

然后经过下面几句代码,就可以使用在页面中插入一个柱状图

chart = new wijmo.chart.FlexChart('#chart');

chart.initialize({

    itemsSource: collectionView,

    bindingX: 'name',

    options: {

        groupWidth: 15

    },

    series: [

        { name: '年龄', binding: 'age' },

    ]

});

   

下面看效果

 

其中,颜色和柱状图的形状可以调整的。当鼠标移到元素上,还有会小提示。

在这里,只需要改变一下chart的类型,就可以切换为其他类型的图表

chart.chartType = chart.chartType === wijmo.chart.ChartType.Column ?

    wijmo.chart.ChartType.Area :

    wijmo.chart.ChartType.Column;

   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标WEB前端JavaScript频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程