首发我的博客 http://blog.meathill.com/tech/js/export-table-data-into-a-excel-file.html

最近接到这么个需求,要把<table>显示的数据导出成Excel表。类似的需求并不稀罕,过去我通常用PHP输出.csv文件,不过这次似乎不能这么做:数据源表格允许用户筛选和排序,与原始数据表有区别,而传递操作又比较麻烦;另外.csv文件的功能受限严重,难以扩展。所以我准备尝试下别的做法。

Google之,发现HTML5又成了一座分水岭。之前在IE浏览器下,用户可以利用ActiveXObject创建Excel.application对象来处理——当然不兼容Mac。后来Excel开放标准,可以导出xml格式的文件,dataURI就有了用武之地,导出<table>数据并保存为Excel有了更好的选择。

(以下内容与StackOverflow中的答案有重合,那个3条赞同的我认为是最佳答案,可惜我没法顶他……)

准备工作

  1. 创建一个空白的Excel文档
  2. 另存为“XML表格”,xml格式
  3. 好了,模版搞定

图省事儿的也可以直接使用我的模板(这一段我使用了Handlebars,以便将来填充数据)

template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">\
<head><!--[if gte mso 9]>\
<xml>\
<x:ExcelWorkbook>\
<x:ExcelWorksheets>\
<x:ExcelWorksheet>\
<x:Name>{{worksheet}}</x:Name>\
<x:WorksheetOptions>\
<x:DisplayGridlines/>\
</x:WorksheetOptions>\
</x:ExcelWorksheet>\
</x:ExcelWorksheets>\
</x:ExcelWorkbook>\
</xml><![endif]-->\
</head>\
<body>\
{{#each tables}}<table>{{{this}}}</table>{{/each}}\
</body>\
</html>';

复制表格数据

复制数据比较简单了。如前面模版所示,这里我很野蛮的直接复制theadtbody的全部代码,填充内容。当然为了体现用户操作,我只复制显示的tr。这里需要注意的是,jQuery判断一个dom是否处于显示状体基于以下3点:

  1. display:none
  2. 表单元素,type="hidden"
  3. 宽高为0
  4. 父级以上节点不显示,自己也不会显示

所以,不能先clone()find(':hidden').remove(),因为没添加到主Dom树的节点宽高都是0,也就会被认为还没显示,这下就都干掉了。

输出内容

套用模版之后,我们就有了完整的表格数据。接下来,我们需要把其转换成base64格式,以便套用dataURI输出。于是便要使用btoa这个函数(将二进制数据转换成base64格式的字符串,HTML5的大礼之一,操作二进制的API),不过注意,这个函数不能直接转换普通unicode字符,不然大多数浏览器都会抛出异常。所以需要先经过两步转换:

function base64(string) {
return window.btoa(unescape(encodeURIComponent(string)));
}

(MDN中还推荐了另外一种做法,通过Typed Array做中介,我没有实操,有兴趣的可以试下)

然后配上base64头和mime类型,就可以触发下载了:

var uri = 'data:application/vnd.ms-excel;base64,';
location.href = uri + base64(template(tables));

提升体验

貌似到这里就完成了,不过作为一名挂职产品总监的码农,我很难容忍下载的文件文件名是“下载”,而且还没有扩展名(Windows 8下没有;Windows 7 和 Mac下会有.xls的扩展名,我认为和已装软件注册过的mime类型有关)。

这是个用在内部管理后台的需求,我之前曾要求大家必须使用Chrome访问后台;而且我知道,Chrome已经支持<a>里的download属性。那么这就好办了,因为onclick事件会先于系统默认行为触发,所以我可以在这个事件的处理函数中将生成的Base64放在被点击按钮的href里,并将其download属性设为容易理解的“某年某月末日至某年某月某日广告数据分析.xls”。至此,此项功能宣告圆满。

HTML部分(使用到Bootstrap和Handlebars):

<a href="#" title="点击下载" class="btn btn-primary export-button" download="{{start}}至{{end}}广告数据分析.xls"><i class="icon-download-alt icon-white"></i> 导出</a>

JavaScript部分

tableToExcel: function (tableList, name) {
var tables = [],
uri = 'data:application/vnd.ms-excel;base64,',
template = Handlebars.compile('<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{{worksheet}}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>{{#each tables}}<table>{{{this}}}</table>{{/each}}</body></html>'); for (var i = 0; i < tableList.length; i++) {
tables.push(tableList[i].innerHTML);
}
var data = {
worksheet: name || 'Worksheet',
tables: tables
};
return uri + base64(template(data));
},
exportHandler: function (event) {
var tables = this.$('table'),
table = null;
tables.each(function (i) {
var t = $('<table><thead></thead><tbody></tobdy></table>');
t.find('thead').html(this.tHead.innerHTML);
t.find('tbody').append($(this.tBodies).children(':visible').clone());
t.find('.not-print').remove(); // not-print 是@media print中不会打印的部分
t.find('a').replaceWith(function (i) { // 表格中不再需要的超链接也移除了
return this.innerHTML;
});
table = table ? table.add(t) : t;
});
event.currentTarget.href = Dianjoy.utils.tableToExcel(table, '广告数据');
}

尾声

说是圆满,其实也不尽然,因为URL有2M的长度限制,遇到真正的大表仍然可能出问题(我没实测)。

最后例行吐槽:老板(领导)想提升工作效率,光逼员工没啥意义,必须关注员工日常使用的软件:不许用乱七八糟的浏览器,统一Chrome;360一率禁用(最近遇到N起升级Chrome Dev 30版导致各种bug的问题);全部装Windows 8(自带杀毒,几乎所有外设秒配)。能做到这几点,公司办公效率提升1倍不止。

再多说两句:我们对外的后台虽然做到了基本兼容,但如果用户使用非Chrome访问,仍然会建议他换用Chrome。目前Chrome访问占比已经上升到90%,IE678不到5%,希望不久的将来,我们的用户都能尽情享受HTML5带来的优秀体验,我们的开发成本也能降得更低。

【HTML5版】导出Table数据并保存为Excel的更多相关文章

  1. 爬取表格类网站数据并保存为excel文件

    本文转载自以下网站:50 行代码爬取东方财富网上市公司 10 年近百万行财务报表数据 https://www.makcyun.top/web_scraping_withpython6.html 主要学 ...

  2. 存储过程—导出table数据为inser sqlt语句

    Sql Server Management Studio没有将table中数据导出为insert语句的功能. 下面一个很有用的存储过程,可以把某张表的数据导出为insert sql语句.当然Oracl ...

  3. jsp导出table数据excel表

    <html> <head> <meta http-equiv="content-Type" content="text/html;chars ...

  4. ArcMap 导出Table数据到Excel

  5. 导出表格数据到excel并下载(HSSFWorkbook版)

    这里主要前面是通过一个全局变量,在layui的done回调里拿到数据,然后将该数据导出到excel,这里要注意一点,下载excel不能用ajax方式,如果采用ajax下载默认会读取response返回 ...

  6. html5中 table数据导出到excel文件

    JS代码: /** * table数据导出到excel * 形参 table : tableId ; * sheetName : 工作薄名 * fileName : 文件名 * linkId :隐藏的 ...

  7. mfc 导出数据保存成excel和txt格式

    最近做了一些东西,项目到了收尾的工作.不过这次我没有参与到控件机器的功能的那一部分,都是主管自己写的.不过,所有的控件重写都是由我来做的.还有数据库这一方面是我和主管共同完成的.不过还不错,主管写一部 ...

  8. 前端Table数据导出Excel使用HSSFWorkbook(Java)

    一.实现原理: 1. 前端查询列表数据并渲染至table(<table>...</table>)表格 2. 表格html代码传输至后台 3. 后台把html转成Excel输出流 ...

  9. 使用pandas导出PostgreSQL 模式下的所有表数据并保存

    PostgreSQL PostgreSQL 是一个非常强大的数据库,它是一个免费的对象-关系数据库服务器(数据库管理系统).PostgreSQL支持大部分 SQL 标准, 在语句上也有很大的相似的地方 ...

随机推荐

  1. html页面跳转出现中文乱码

    一般html的<meta charset="UTF-8">默认都是utf-8的编码格式,直接在网页中打开是正常的,但是有的时候在页面跳转时就会出现中文乱码问题,忘了参考 ...

  2. SQL Server--插入一天数据返回ID值

    这里将该功能写成了一个存储过程, 本来只写Insert的话,返回1,即影响的行数,该数据没太大应用意义. 想在Insert的基础上,返回新添加的这条数据的ID,两种方法: 1 .添加第17行的Sele ...

  3. 解决 Vue 项目 invalid host header 问题(两种方案)

    问题出现背景 做微信H5网页时,使用花生壳内网穿透进行调试时,打开网页显示:invalid host header 分析问题 这句话的意思是:无效的Host请求头: 因为在vue在调试时相当于启动了一 ...

  4. tensorflow源码解析之framework拾遗

    把framework中剩余的内容,按照文件名进行了简单解析.时间原因写的很仓促,算是占个坑,后面有了新的理解再来补充. allocation_description.proto 一个对单次内存分配结果 ...

  5. Spark ML源码分析之三 分类器

            前面跟大家扯了这么多废话,终于到具体的机器学习模型了.大部分机器学习的教程,总要从监督学习开始讲起,而监督学习的众多算法当中,又以分类算法最为基础,原因在于分类问题非常的单纯直接,几乎 ...

  6. 面试官:Redis如何实现持久化的、主从哨兵又是什么?

    哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 作为一名Java程序员,Redi ...

  7. 25 面向对象编程 继承概念 代码 快捷键 super注意点

    继承概念 继承的本质是对某一批的抽象,从而实现对现实世界更美好的建模. extends的意思的"扩展".子类是父类的扩展. JAVA中类只有单继承,没有多继承!理解:一个儿子只能有 ...

  8. 【黑马程序员C++ STL】学习记录

    黑马程序员 2017 C++ STL 教程(STL 部分已完结) 基于黑马STL课程整理:黑马程序员2017C++STL教程 视频链接 专栏:本STL专栏目录 文章目录 黑马程序员 2017 C++ ...

  9. 一步一步迁移ASP.NET Core 6.0-Part2

    .NET 6 发布后,我们现有的应用会逐步升级到这个版本,首当其冲的是原因的ASP.NET Core的工程,如果一步一步升级到ASP.NET Core 6.0. 上一篇博文中,跟大家详细介绍了中间件. ...

  10. 配置文件 /etc/profile出错导致ls,vi不能用

    配置文件 /etc/profile出错导致ls,vi不能用   关于 Linux 的配置文件 /etc/profile 路径出错后相关的命令失效解决方式(如:ls,vi不能用)   一般我记得vi是在 ...