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 this 的一些学习总结
Aug 31 Javascript
jQuery提交多个表单的小例子
Jun 30 Javascript
jquery中插件实现自动添加用户的具体代码
Nov 15 Javascript
JavaScript代码复用模式详解
Nov 07 Javascript
javascript实现简单的分页特效
Aug 12 Javascript
jQuery实现百叶窗焦点图动画效果代码分享(附源码下载)
Mar 14 Javascript
原生js实现无缝轮播图效果
Jan 11 Javascript
Bootstrap下拉菜单Dropdowns的实现代码
Mar 17 Javascript
Javascript创建类和对象详解
May 31 Javascript
Angular2 自定义validators的实现方法
Jul 05 Javascript
vue better scroll 无法滚动的解决方法
Jun 07 Javascript
js中的reduce()函数讲解
Jan 18 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
Windows下PHP5和Apache的安装与配置
2006/09/05 PHP
新浪新闻小偷
2006/10/09 PHP
php str_replace的替换漏洞
2008/03/15 PHP
PHP安装memcached扩展笔记
2015/05/28 PHP
统一接口:为FireFox添加IE的方法和属性的js代码
2007/03/25 Javascript
JavaScript Undefined,Null类型和NaN值区别
2008/10/22 Javascript
JavaScript怎么判断图片是否加载完成以便获取其尺寸
2014/05/08 Javascript
js图片轮播手动切换效果
2015/11/10 Javascript
js滚动条平滑移动示例代码
2016/03/29 Javascript
封装的dialog插件 基于bootstrap模态对话框的简单扩展
2016/08/10 Javascript
Vue生命周期示例详解
2017/04/12 Javascript
VUE实现表单元素双向绑定(总结)
2017/08/08 Javascript
基于vue的短信验证码倒计时demo
2017/09/13 Javascript
JS实现的DOM插入节点操作示例
2018/04/04 Javascript
vue组件定义,全局、局部组件,配合模板及动态组件功能示例
2019/03/19 Javascript
vue.js 2.*项目环境搭建、运行、打包发布的详细步骤
2019/05/01 Javascript
python 随机数生成的代码的详细分析
2011/05/15 Python
python绘图库Matplotlib的安装
2014/07/03 Python
深入学习python的yield和generator
2016/03/10 Python
Python实现找出数组中第2大数字的方法示例
2018/03/26 Python
python将list转为matrix的方法
2018/12/12 Python
python3实现二叉树的遍历与递归算法解析(小结)
2019/07/03 Python
django-rest-framework 自定义swagger过程详解
2019/07/18 Python
PythonPC客户端自动化实现原理(pywinauto)
2020/05/28 Python
.net笔试题
2014/03/03 面试题
临床医师专业个人自我评价范文
2013/11/07 职场文书
上课睡觉检讨书
2014/01/28 职场文书
元旦文艺汇演主持词
2014/03/26 职场文书
餐饮商业计划书范文
2014/04/29 职场文书
班级年度安全计划书
2014/05/01 职场文书
试用期员工工作自我评价
2014/09/10 职场文书
2014年专项整治工作总结
2014/11/17 职场文书
2015年施工员工作总结范文
2015/04/20 职场文书
社交电商模式的兴起:这些新的商机千万别错过
2019/07/26 职场文书
CSS实现多个元素在盒子内两端对齐效果
2021/03/30 HTML / CSS
使用jpa之动态插入与修改(重写save)
2021/11/23 Java/Android