JavaScrip如果基于url实现图片下载


Posted in Javascript onJuly 03, 2020

1.H5 download属性

function downFile(content, filename) {
  // 创建隐藏的可下载链接
  var eleLink = document.createElement('a');
  eleLink.download = filename;
  eleLink.style.display = 'none';
  // 字符内容转变成blob地址
  var blob = new Blob([content]);
  eleLink.href = URL.createObjectURL(blob);
  // 触发点击
  document.body.appendChild(eleLink);
  eleLink.click();
  // 然后移除
  document.body.removeChild(eleLink);
};

downFile(下载地址, 保存名称);

2.iframe方式

// if (typeof(download.iframe) == 'undefined') {
      //   var iframe = document.createElement('iframe');
      //   download.iframe = iframe;
      //   document.body.appendChild(download.iframe);
      // };
      // download.iframe.src = newdownloadUrl;
      // download.iframe.style.display = "none";

3.form方式

// var $eleForm = $("<form method='get'></form>");
      // $eleForm.attr("action", "https://codeload.github.com/douban/douban-client/legacy.zip/master");
      // $eleForm.attr("action", url);
      // $(document.body).append($eleForm);
      // $eleForm.submit();

downloadIamge(imgsrc, name) {//下载图片地址和图片名
 let image = new Image();
 // 解决跨域 Canvas 污染问题
 image.setAttribute("crossOrigin", "anonymous");
 image.onload = function() {
  let canvas = document.createElement("canvas");
  canvas.width = image.width;
  canvas.height = image.height;
  let context = canvas.getContext("2d");
  context.drawImage(image, 0, 0, image.width, image.height);
  let url = canvas.toDataURL("image/png"); //得到图片的base64编码数据
  let a = document.createElement("a"); // 生成一个a元素
  let event = new MouseEvent("click"); // 创建一个单击事件
  a.download = name || "photo"; // 设置图片名称
  a.href = url; // 将生成的URL设置为a.href属性
  a.dispatchEvent(event); // 触发a的单击事件
 };
 image.src = imgsrc;
},

原理

我们先看看 download 的使用方法:

<a href="http://somehost/somefile.zip" rel="external nofollow" rel="external nofollow" download="filename.zip">Download file</a>

看看上面的代码,只要为 <a> 标签添加 download 属性,我们点击这个链接的时候就会自动下载文件了~

顺便说下,download 的属性值是可选的,它用来指定下载文件的文件名。像上面的例子中,我们下载到本地的文件名就会是 filename.zip 拉,如果不指定的话,它就会是 somefile.zip 这个名字拉!

看到这里,你可能会说,坑爹啊,这明明是用 HTML 5 的新特性来实现下载文件嘛,说好的用 JavaScript 下载文件呢?

事实上,用 JavaScript 来下载文件也是利用这一特性来实现的,我们的 JavaScript 代码不外乎就是:

  • 用 JavaScript 创建一个隐藏的 <a> 标签
  • 设置它的 href 属性
  • 设置它的 download 属性
  • 用 JavaScript 来触发这个它的 click 事件

翻译成 JavaScript 代码就是:

var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
var filename = 'what-you-want.txt';
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);

好拉,是不是看到有个陌生的东东呢?

window.URL

window.URL 里面有两个方法:

createObjectURL 用 blob 对象来创建一个 object URL(它是一个 DOMString),我们可以用这个 object URL 来表示某个 blob 对象,这个 object URL 可以用在 href 和 src 之类的属性上。

revokeObjectURL 释放由 createObjectURL 创建的 object URL,当该 object URL 不需要的时候,我们要主动调用这个方法来获取最佳性能和内存使用。

知道了这两个方法之后,我们再回去看看上面的例子就很容易理解了吧!只是用 blob 对象来创建一条 URL,然后让 <a> 标签引用该 URL,然后触发个点击事件,就可以下载文件了!

那么问题来了,blob 对象哪里来?

Blob 对象

Blob 全称是 Binary large object,它表示一个类文件对象,可以用它来表示一个文件。根据 MDN 上面的说法,File API 也是基于 blob 来实现的。

由于本文的主题是讲 JavaScript 下载文件,那我们构建 blob 的方式就是通过服务器返回的文件来创建 blob 拉!
而最简单的方式就是用 fetch API 了,我们可以整合上面的例子:

fetch('http://somehost/somefile.zip').then(res => res.blob().then(blob => {
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
var filename = 'myfile.zip';
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}))

很简单对吧!

你可能会问,何必这么麻烦呢?直接写成下面这样不就好了:

<a href="http://somehost/somefile.zip" rel="external nofollow" rel="external nofollow" download="myfile.zip">Download file</a>
嗯,对于这种写法,我只能说,你做的太正确了!如果你要下载的是已经存在服务器上面的静态文件的话,那么写成这样是最方便的。浏览器会帮你处理整个下载过程,不需要你干涉。如果你用 blob 的方式来下载文件的话,会有下面这些限制的:

限制一:不同浏览器对 blob 对象有不同的限制

具体看看下面这个表格(出自 FileSaver.js):

Browser Constructs as Filenames Max Blob Size Dependencies
Firefox 20+ Blob Yes 800 MiB None
Firefox data: URI No n/a Blob.js
Chrome Blob Yes 500 MiB None
Chrome for Android Blob Yes 500 MiB None
Edge Blob Yes ? None
IE 10+ Blob Yes 600 MiB None
Opera 15+ Blob Yes 500 MiB None
Opera data: URI No n/a Blob.js
Safari 6.1+* Blob No ? None
Safari data: URI No n/a Blob.js

限制二:构建完 blob 对象后才会转换成文件

这一点限制对小文件(几十kb)可能没什么影响,但对稍微大一点的文件影响就很大了。试想,用户要下载一个 100mb 的文件,如

果他点击了下载按钮之后没看到下载提示的话,他肯定会继续按,等他按了几次之后还没看到下载提示时,他就会抱怨我们的网站,然后离开了。

然而事实上下载的的确确发生了,只是要等到下载完文件之后才能构建 blob 对象,再转化成文件。而且,用户再触发多几次下载就会造成一些资源上的浪费。

因此,如果是要下载大文件的话,还是推荐直接创建一个 <a> 标签拉~

写 html 也好,写 JavaScript 动态创建也好,用自己喜欢的方式去创建就好了。

为什么要用 JavaScript 下载文件

好拉,说了半天,其实我们一直说的都是:「不要用 JavaScript 下载文件拉,限制多多,又不好用,直接用 html 就好拉,简单方便又快捷」这个论调。

事实上也确实如此,但有些时候我们确实需要通过 JavaScript 来做一些预处理。

权限校验

有些时候,我们需要对下载做一些限制,最常见的就是权限校验了,如检查该用户是否有下载的权限,是否有高速下载的权限等等。这时候,我们可以利用 JavaScript 做一些预处理。如:

fetch('http://somehost/check-permission', options).then(res => {
if (res.code === 0) {
var a = document.createElement('a');
var url = res.data.url;
var filename = 'myfile.zip';
a.href = url;
a.download = filename;
a.click();
} else {
alert('You have no permission to download the file!');
}
});

在这个例子里面,我们没有用 blob 来构建 URL,而是通过后端服务器来计算出用户的下载链接,然后再利用之前提到的动态创建 <a> 标签的方式来实现下载,很简单吧!

动态文件

动态生成文件然后返回给客户端也是一个很常见的需求,譬如我们有时候需要做导出数据的功能,把数据库中的某些数据导出到 Excel 中,然后再返回客户端。

这时候我们就不能简单的指定 href 属性,因为对应的 URL 并不存在。

我们只能通过 JavaScript 对服务器发出一个请求,通知它去生成某个文件,然后把对应的 URL 返回给客户端。

有没有感觉这个过程和上面「权限校验」一节很像?肯定拉,因为我们只是对 URL 做了一些预处理而已嘛~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript模拟的Ping效果代码 (Web Ping)
Mar 13 Javascript
js监听鼠标点击和键盘点击事件并自动跳转页面
Sep 24 Javascript
实现前后端数据交互方法汇总
Apr 07 Javascript
jQuery移动web开发之页面跳转和加载外部页面的实现
Dec 04 Javascript
Javascript中八种遍历方法的执行速度深度对比
Apr 25 Javascript
React中使用collections时key的重要性详解
Aug 07 Javascript
JS库 Highlightjs 添加代码行号的实现代码
Sep 13 Javascript
微信小程序使用wxParse解析html的方法教程
Jul 06 Javascript
vue中引用swiper轮播插件的教程详解
Aug 16 Javascript
搭建基于express框架运行环境的方法步骤
Nov 15 Javascript
微信小程序绘制图片发送朋友圈
Jul 25 Javascript
详解JavaScript匿名函数和闭包
Jul 10 Javascript
基于VUE实现判断设备是PC还是移动端
Jul 03 #Javascript
JavaScript如何判断对象有某属性
Jul 03 #Javascript
详解element-ui动态限定的日期范围选择器代码片段
Jul 03 #Javascript
JS常见错误(Error)及处理方案详解
Jul 02 #Javascript
vue过滤器实现日期格式化的案例分析
Jul 02 #Javascript
Vue使用预渲染代替SSR的方法
Jul 02 #Javascript
node运行js获得输出的三种方式示例详解
Jul 02 #Javascript
You might like
PHP用户指南-cookies部分
2006/10/09 PHP
php读取mysql乱码,用set names XXX解决的原理分享
2011/12/29 PHP
ThinkPHP使用心得分享-ThinkPHP + Ajax 实现2级联动下拉菜单
2014/05/15 PHP
php验证身份证号码正确性的函数
2016/07/20 PHP
jQuery的实现原理的模拟代码 -3 事件处理
2010/08/03 Javascript
JavaScript String.replace函数参数实例说明
2013/06/06 Javascript
JavaScript字符串对象slice方法入门实例(用于字符串截取)
2014/10/16 Javascript
Javascript基础教程之关键字和保留字汇总
2015/01/18 Javascript
jQuery实现监控页面所有ajax请求的方法
2015/12/10 Javascript
js纯数字逐一停止显示效果的实现代码
2016/03/16 Javascript
JS中对Cookie的操作详解
2016/08/05 Javascript
vue.js+Element实现表格里的增删改查
2017/01/18 Javascript
p5.js实现动态图形临摹
2019/10/23 Javascript
JavaScript Date对象功能与用法学习记录
2020/04/28 Javascript
解决vue单页面多个组件嵌套监听浏览器窗口变化问题
2020/07/30 Javascript
js实现点击上传图片并设为模糊背景
2020/08/02 Javascript
Openlayers实现扩散的动态点(水纹效果)
2020/08/17 Javascript
[02:32]DOTA2亚洲邀请赛 VG战队巡礼
2015/02/03 DOTA
python实现数通设备tftp备份配置文件示例
2014/04/02 Python
Python多线程编程简单介绍
2015/04/13 Python
编写Python的web框架中的Model的教程
2015/04/29 Python
Python解析最简单的验证码
2016/01/07 Python
Python反射用法实例简析
2017/12/22 Python
详解css3 mask遮罩实现一些特效
2018/10/24 HTML / CSS
使用CSS3制作一个简单的Chrome模拟器
2015/07/15 HTML / CSS
金宝贝童装官网:Gymboree
2016/08/31 全球购物
美国时尚孕妇装品牌:A Pea in the Pod
2017/07/16 全球购物
CheapTickets泰国:廉价航班,查看促销价格并预订机票
2019/12/28 全球购物
贝佳斯官方网站:Borghese
2020/05/08 全球购物
文员自我评价怎么写
2013/09/19 职场文书
师德学习感言
2014/01/31 职场文书
校园安全广播稿
2014/02/08 职场文书
《夕阳真美》教学反思
2014/04/27 职场文书
关爱老人标语
2014/06/21 职场文书
学生偷窃检讨书
2014/09/25 职场文书
2014年电教工作总结
2014/12/19 职场文书