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" 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" 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 < 20 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 < 15 data: URI No n/a Blob.js
Safari 6.1+* Blob No ? None
Safari < 6 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 做了一些预处理而已嘛~

js 根据url 下载图片的更多相关文章

  1. js 根据url 下载图片 前端js 实现文件下载

    1.H5 download属性 function downFile(content, filename) { // 创建隐藏的可下载链接 var eleLink = document.createEl ...

  2. C++根据图片url下载图片

    需要使用到URLDownloadToFile()函数,该函数在头文件<urlmon.h>中声明. URLDownloadToFile()函数的定义如下: HRESULT URLDownlo ...

  3. 从url下载图片--java与python实现方式比较

    从url下载图片--java与python实现方式比较 博客分类: 技术笔记小点滴 javapython图片下载  一.java的实现方式 首先读取图片 //方式一:直接根据url读取图片 priva ...

  4. JAVA 通过url下载图片保存到本地

    //java 通过url下载图片保存到本地 public static void download(String urlString, int i) throws Exception { // 构造U ...

  5. QT通过url下载图片到本地

    /* strUrl:下载图片时需要的url strFilePath:下载图片的位置(/home/XXX/YYY.png) */ void ThorPromote::downloadFileFromUr ...

  6. 根据URL地址获取对应的HTML,根据对应的URL下载图片

    核心代码(获取HTML): #region 根据URL地址获取信息GET public static String GetResult(string url) { return GetResult(u ...

  7. 根据URL下载图片到本地

    /// <summary> /// 下载图片 /// </summary> /// <param name="picUrl">图片Http地址& ...

  8. python实现通过URL下载图片到本地服务器

    import os import urllib.request image_url = 'http://img.jingtuitui.com/759fa20190115144450401.jpg' f ...

  9. Java依据Url下载图片

    package com.ronniewang.downloadpicture; import java.io.DataInputStream; import java.io.File; import ...

随机推荐

  1. Centos7下安装Oracle11g r2

    我的centos7是在virtualbox下安装的,安装Oracle安装了好久好久,最开始的时候在网上找的两个文章,按照步骤装,有一篇写着装的时候有灰色的竖线,直接按space键或者鼠标右键close ...

  2. 关于Amazon.com Seller 网络以及IP地址更换 官方回答

    Greetings from Amazon Seller Support, I understand your concern that there will be a change of IP ad ...

  3. 用vsstudio 设计Winform 高分屏上布局错乱的问题

    在使用win10高分辨率150%,200%系统进行winform开发时, 会有布局错乱的现象,比如之前定义的300px的宽度,往往被设置成600px (200%分辨率下). 这个问题vs2015的解决 ...

  4. Linux下文件的打包、解压缩指令——tar,gzip,bzip2

    本文是对 鸟叔的Linux私房菜(基础学习篇) 第三版 的学习笔记,原文可参考原书中文网站 鸟叔的Linux私房菜.更多详细信息可直接参考对应Linux命令的 man 帮助( 如 man tar). ...

  5. Codeforces Round #765 Div.1 F. Souvenirs 线段树

    题目链接:http://codeforces.com/contest/765/problem/F 题意概述: 给出一个序列,若干组询问,问给出下标区间中两数作差的最小绝对值. 分析: 这个题揭示着数据 ...

  6. underscore.js源码解析(三)

    最近工作比较忙,做不到每周两篇了,周末赶着写吧,上篇我针对一些方法进行了分析,今天继续. 没看过前两篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二 ...

  7. t2

    测评项目 : 福大助手 组长博客链接:https://www.cnblogs.com/dawnduck/p/10093752.html 第一部分:调研,评测 评测 1. 第一次上手体验 安卓: 进入页 ...

  8. Spring学习(六)—— Spring注解(二)

    核心原理 1.       用户发送请求给服务器.url:user.do 2.       服务器收到请求.发现Dispatchservlet可以处理.于是调用DispatchServlet. 3.  ...

  9. Struts2(六)

    以下内容是基于导入struts2-2.3.32.jar包来讲的 1.OGNL OGNL是Object-Graph Navigation Language的缩写,全称为对象图导航语言,是一种功能强大的表 ...

  10. js登录界面代码自用

    var btn = document.getElementById("a4"); var usne = document.getElementById("username ...