JS实现弹出下载对话框及常见文件类型的下载


Posted in Javascript onJuly 13, 2017

1.写在前面

JS要实现下载功能,一般都是这么几个过程:生成下载的URL,动态创建一个A标签,并将其href指向生成的URL,然后触发A标签的单击事件,这样就会弹出下载对话框,从而实现了一个下载的功能。

这里所说的下载,有时候也可以理解为保存。出于安全考虑,JS肯定无法直接调用FileAPI写文件到磁盘,但是却可以通过下载来变相实现保存功能。

2.几个备用知识点

2.1. JS触发单击事件

既然是用A标签模拟,那么肯定要知道JS如何主动触发单击事件。

最简单的触发单击事件肯定是elem.click(),平时在不需要考虑兼容性的场合我都是这么干的,但是毕竟这个方法有兼容性(具体兼容性如何没做过测试),所以还是要掌握一个通用的方法。

以下代码是网上比较容易找到的一段代码,我在前面加了一段MouseEvent的判断:

/**
 * 触发单击事件
 * @param elem 需要触发事件的DOM对象
 */
function fireClickEvent(elem)
{
 var event;
 if(window.MouseEvent) event = new MouseEvent('click');
 else
 {
  event = document.createEvent('MouseEvents');
  event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
 }
 elem.dispatchEvent(event);
}

2.2. HTML5的download属性

这个属性很重要,它可以指定下载文件名,并且可以告诉浏览器目标链接是一个下载链接,不是一个普通链接,我们看下面代码就能看出区别了:

<a href="data:text/txt;charset=utf-8,测试下载纯文本" rel="external nofollow" rel="external nofollow" rel="external nofollow" download="测试.txt" >下载1</a>
<a href="data:text/txt;charset=utf-8,测试下载纯文本" rel="external nofollow" rel="external nofollow" rel="external nofollow" >下载2</a>

可以发现,下载1按钮能够实现下载,点击下载2链接时直接在浏览器打开文件内容了。

补充说明:

file:///模式下貌似不生效;

链接指向一些第三方链接时也不会生效,具体有待研究;

2.3. JS弹出下载对话框

假如给我们的不是一个下载地址而是一个blob对象,我们可以通过URL.createObjectURL来给blob对象生成临时URL,并且可以利用HTML5的download属性来指定下载的文件名,好家伙,有了这2个东西我们就可以实现一个“万能”的弹出下载对话框方法了。

综上所述,我又在fireClickEvent的基础上继续简单封装了一个openDownloadDialog方法,使用如下:

openDownloadDialog(url, saveName)
openDownloadDialog(blob, saveName)

代码如下:

/**
 * 通用的打开下载对话框方法,没有测试过具体兼容性
 * @param url 下载地址,也可以是一个blob对象,必选
 * @param saveName 保存文件名,可选
 */
function openDownloadDialog(url, saveName)
{
 if(typeof url == 'object' && url instanceof Blob)
 {
  url = URL.createObjectURL(url); // 创建blob地址
 }
 var aLink = document.createElement('a');
 aLink.href = url;
 aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
 var event;
 if(window.MouseEvent) event = new MouseEvent('click');
 else
 {
  event = document.createEvent('MouseEvents');
  event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
 }
 aLink.dispatchEvent(event);
}

3.JS实现常见文件类型的下载

3.1. JS生成CSV文件并下载

csv是一种逗号分隔的表格文件格式,可以很好的被Excel支持,由于其文件格式简单,所以经常用在简单的表格上面。最重要的是它是一种纯文本格式,可以很轻松地用JS来生成而不借助第三方库。

3.1.1. CSV格式示例

如下:

姓名,期中成绩,期末成绩
张三,58,95
李四,98,74
王二,47,38
刘能,15,100
黄五,87,68

excel打开效果如下:

JS实现弹出下载对话框及常见文件类型的下载

3.1.2. 初次尝试

首先想到的是使用data:text/txt;来实现,先看一下下载纯文本:

<a download="测试.txt" href="data:text/txt;charset=utf-8,测试下载纯文本" rel="external nofollow" rel="external nofollow" rel="external nofollow" >下载</a>

以上代码没毛病,然后再换成csv。换csv的最大问题就是如何处理换行,很简单,用encodeURIComponent编码一下就可以了:

<button onclick="test()">下载CSV</button>
<script>
function test()
{
 var csv = '姓名,期中成绩,期末成绩\n张三,58,95\n李四,98,74';
 var a = document.createElement('a');
 a.href = 'data:text/txt;charset=utf-8,'+encodeURIComponent(csv);
 a.download = '测试.csv';
 a.click(); // 这里偷个懒,直接用click模拟
}
</script>

3.1.3. 解决CSV乱码问题

虽然我们用的是UTF-8编码,下载后你会发现,用文本编辑器打开没问题,但是用Excel打开乱码:

别急,原因就是少了一个\ufeffBOM头,改成这样就没问题了:

<button onclick="test()">下载CSV</button>
<script>
function test()
{
 var csv = '姓名,期中成绩,期末成绩\n张三,58,95\n李四,98,74';
 var a = document.createElement('a');
 a.href = 'data:text/txt;charset=utf-8,\ufeff'+encodeURIComponent(csv);
 a.download = '测试.csv';
 a.click(); // 这里偷个懒,直接用click模拟
}
</script>

3.1.4. 继续解决下载文件名的问题

大部分浏览器可能都没啥问题,但是一些比较老的Chrome可能下载的时候指定的download就是不生效,此时可以用blob来解决:

var csv = '姓名,期中成绩,期末成绩\n张三,58,95\n李四,98,74';
var blob = new Blob(['\ufeff' + data], {type: 'text/csv,charset=UTF-8'});
openDownloadDialog(blob, '测试.csv');

建议一般情况下都用这种方法,稳妥一点。

3.1.5. 最后总结

不考虑兼容性的保存CSV方法:

/**
 * 保存CSV文件
 * @params csv csv文件内容
 * @params saveName 保存的文件名
 */
function saveCSV(csv, saveName)
{
 var a = document.createElement('a');
 a.href = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(csv);
 a.download = saveName;
 a.click();
}

考虑兼容性的保存CSV方法:

/**
 * 保存CSV文件
 * @params csv csv文件内容
 * @params saveName 保存的文件名
 */
function saveCSV(csv, saveName)
{
 var blob = new Blob(['\ufeff' + csv], {type: 'text/csv,charset=UTF-8'});
 openDownloadDialog(blob, saveName);
}

3.2. JS实现纯文本的下载保存

掌握了csv,再去下载纯文本基本上就没啥问题了,就是换一下文件类型而已:

var csv = '你好,我是小茗同学!\n测试换行!';
var blob = new Blob([data], {type: 'text/txt,charset=UTF-8'});
openDownloadDialog(blob, '测试.csv');

3.3. JS实现图片的下载保存

网页上一般要保存图片都是从canvas里面拿到的图片数据,通过toDataURL转换为base64数据:

/**
 * 将某个canvas保存为图片
 * @param canvasObj canvas对象
 * @param saveName 保存的名称
 * @param type 保存的图片格式,如 image/png
 * @param quality 图片质量,可选0-1
 */
function saveImage(canvasObj, saveName, type, quality)
{
 if(!canvasObj) return;
 type = type || 'image/png';
 quality = quality || 0.92;
 var url = canvasObj.toDataURL(type, quality).replace(/image\/.*?;/, 'image/octet-stream;');
 openDownloadDialog(url, saveName);
}

扩展

关于文件保存,不嫌麻烦的话,GitHub上面有个比较出名的库:https://github.com/eligrey/FileSaver.js/

demo:https://eligrey.com/demos/FileSaver.js/

以上所述是小编给大家介绍的JS实现弹出下载对话框及常见文件类型的下载,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
用 javascript 实现的点击复制代码
Mar 24 Javascript
javascript 面向对象,实现namespace,class,继承,重载
Oct 29 Javascript
jquery 图片截取工具jquery.imagecropper.js
Apr 09 Javascript
javascript学习总结之js使用技巧
Sep 02 Javascript
javascript中tostring()和valueof()的用法及两者的区别
Nov 16 Javascript
JS onkeypress兼容性写法详解
Apr 27 Javascript
setTimeout学习小结
Feb 08 Javascript
利用Vue.js实现求职在线之职位查询功能
Jul 03 Javascript
详解JS数组Reduce()方法详解及高级技巧
Aug 18 Javascript
如何利用vue+vue-router+elementUI实现简易通讯录
May 13 Javascript
Node.js API详解之 os模块用法实例分析
May 06 Javascript
ant design charts 获取后端接口数据展示
May 25 Javascript
vue开发调试神器vue-devtools使用详解
Jul 13 #Javascript
基于JS代码实现简单易用的倒计时 x 天 x 时 x 分 x 秒效果
Jul 13 #Javascript
浅谈关于axios和session的一些事
Jul 13 #Javascript
详解JS数据类型的值拷贝函数(深拷贝)
Jul 13 #Javascript
JS+HTML5 FileReader实现文件上传前本地预览功能
Mar 27 #Javascript
js学习总结_选项卡封装(实例讲解)
Jul 13 #Javascript
用户管理的设计_jquery的ajax实现二级联动效果
Jul 13 #jQuery
You might like
Thinkphp搭建包括JS多语言的多语言项目实现方法
2014/11/24 PHP
CodeIgniter连贯操作的底层原理分析
2016/05/17 PHP
yii2.0整合阿里云oss上传单个文件的示例
2017/09/19 PHP
几个有趣的Javascript Hack
2010/07/24 Javascript
基于jquery的多功能软键盘插件
2012/07/25 Javascript
javascript实现禁止复制网页内容
2014/12/16 Javascript
JavaScript将数字转换成大写中文的方法
2015/03/23 Javascript
jQuery简单实现遍历数组的方法
2015/04/14 Javascript
jqTransform美化表单
2015/10/10 Javascript
js制作支付倒计时页面
2016/10/21 Javascript
浅谈AngularJs指令之scope属性详解
2016/10/24 Javascript
JavaScript下拉菜单功能实例代码
2017/03/01 Javascript
详解vue事件对象、冒泡、阻止默认行为
2017/03/20 Javascript
js实现图片旋转 js滚动鼠标中间对图片放大缩小
2017/07/05 Javascript
nodejs密码加密中生成随机数的实例代码
2017/07/17 NodeJs
详解webpack编译速度提升之DllPlugin
2019/02/05 Javascript
jQuery中getJSON跨域原理的深入讲解
2020/09/02 jQuery
实现vuex原理的示例
2020/10/21 Javascript
Python按行读取文件的简单实现方法
2016/06/22 Python
Django自定义用户认证示例详解
2018/03/14 Python
python 叠加等边三角形的绘制的实现
2019/08/14 Python
python实现斗地主分牌洗牌
2020/06/22 Python
JoJo Maman Bébé爱尔兰官网:英国最受欢迎的精品母婴品牌
2020/12/20 全球购物
资产经营总监岗位职责范文
2013/12/01 职场文书
会计学生自我鉴定
2014/02/06 职场文书
优秀学生获奖感言
2014/02/15 职场文书
内衣营销方案
2014/03/15 职场文书
搞笑车尾标语
2014/06/23 职场文书
竞选班干部演讲稿300字
2014/08/20 职场文书
班主任师德师风自我剖析材料
2014/10/02 职场文书
2014大学辅导员工作总结
2014/12/02 职场文书
优秀教师事迹材料
2014/12/15 职场文书
职业生涯规划书之大学四年
2019/08/07 职场文书
《童年》读后感(三篇)
2019/08/27 职场文书
MySQL分库分表与分区的入门指南
2021/04/22 MySQL
postgres之jsonb属性的使用操作
2021/06/23 PostgreSQL