为什么要写这个方法呢
这几天接到一个需求,页面列表中有很多按钮,点击按钮可以下载对应的图片。平时自己上网下载图片都是鼠标右键另存为的,但是这里触发保存的动作是点击下载按钮。只能硬着头皮去网上找答案,原来方法是这么的多:通过a标签下载,通过使用canvas下载,通过使用blob下载,通过使用iframe下载等等。但由于考虑到使用纯前端技术实现和兼容性问题,最终自己总结出两个比较靠谱的方法,并封装成一个工具类,在此分享出来,如有错误还请指出,希望能相互学习。
方法总结
- 方法一:使用a标签的download属性。
如:
<a href="1.jpg" download="1.jpg">下载图片</a>
复制代码
- 方法二:使用iframe标签,其src指向图片地址,另外调用document.execCommand("SaveAs")方法。
但要注意的是在非Trident内核浏览器(即非IE浏览器)下并不支持a标签的下载方法,所以本工具类目的是对其进行封装能够适应大部分的图片下载
代码实现
function DownloadImg() {
this.frame = null; //
this.isIE = !!window.ActiveXObject || ("ActiveXObject" in window);
}
/**
*@param clickId a标签的id值
*@param imgUrl 要下载的图片的路径
*/
DownloadImg.prototype.init = function(clickId, imgUrl) {
var oA = document.getElementById(clickId),
that = this;
/*检测是否为同源图片*/
var imgHost, localHost = location.host,
doubleIndex = imgUrl.indexOf('//');
if (doubleIndex != -1) {
imgHost = imgUrl.substring(doubleIndex + 2, imgUrl.indexOf(doubleIndex + 2));
if (imgHost != localHost) { //如果图片非同源
oA.href = imgUrl;
return;
}
}
/*检测是否为同源图片end*/
if (that.isIE) { //如果是IE浏览器,使用方法二
oA.onclick = function() {
that.createIframe(imgUrl);
}
} else { //如果是非IE浏览器,使用方法一
oA.download = imgUrl.substring(imgUrl.lastIndexOf('/') + 1);
oA.href = imgUrl;
}
}
DownloadImg.prototype.createIframe = function(imgUrl) {
var that = this;
//如果隐藏的iframe不存在则创建
if (!this.frame) {
var oBody = document.getElementsByTagName('body')[0],
frame = document.createElement('iframe');
frame.style.display = 'none';
frame.name = 'downloadIframe';//在IE7下设置好的name属性会变成submitName,用setAttribute设置也是同样效果,待解决
frame.width = 0;
frame.height = 0;
this.frame = frame;
// this.frame.onload = this.downloadImg();//这种方式绑定会有问题,待解决
this.addEvent(this.frame, 'load', function() { //给iframe绑定一个load方法,load完成便会触发下载方法
that.downloadImg();
})
oBody.appendChild(this.frame); //将创建的iframe添加到body中
}
if (this.frame.src != imgUrl) { //如果本次要下载的图片路径不等于上一次下载的图片路径,那么对iframe进行重新赋值,那么又将会触发load事件,从而间接的触发下载事件
this.frame.src = imgUrl;
} else { //如果本次要下载的图片路径等于上一次下载的图片路径,直接调用下载图片方法
this.downloadImg();
}
}
DownloadImg.prototype.downloadImg = function() {
if (this.frame.src != '' && this.frame.src != 'about:blank') { //如果iframe的src路径存在那么调用下载浏览器的保存方法
window.frames["downloadIframe"].document.execCommand("SaveAs");
}
}
DownloadImg.prototype.addEvent = function(el, eventType, handler) { //事件兼容
if (el.attachEvent) {
el.attachEvent('on' + eventType, handler);
} else if (el.addEventListener) {
el.addEventListener(eventType, handler, false);
} else {
el['on' + eventType] = handler;
}
}
复制代码
工具类的使用
//实例化这个工具类
var downloadImg = new DownloadImg();
//传入a标签的id,和要分别下载的图片地址进行初始化
downloadImg.init('download', 'https://gss0.bdstatic.com/5bVWsj_p_tVS5dKfpU_Y_D3/res/r/image/2017-09-27/297f5edb1e984613083a2d3cc0c5bb36.png');
downloadImg.init('download1', './imgs/1.png');
复制代码
注意的问题
-
这两种方法实现点击下载的前提是要下载的图片是同源的,那么意味着其他网站的图片是不能实现点击下载的。如果使用本方法,在非IE浏览器中会直接跳转到该图片的预览地址,而在IE浏览器下则直接报错,因此该工具对此进行了优雅降级,如果是非同源图片,直接进行跳转预览,让用户自己鼠标右键另存为去吧~~
-
这里点击下载的实现都是由a标签触发的,因此在页面上的按钮也需要使用该标签来书写
-
这里没有做过多的优化处理和参数检测,初始化的时候只能传入一个id,和一个字符串格式的图片路径