前端实现点击下载图片

为什么要写这个方法呢

     这几天接到一个需求,页面列表中有很多按钮,点击按钮可以下载对应的图片。平时自己上网下载图片都是鼠标右键另存为的,但是这里触发保存的动作是点击下载按钮。只能硬着头皮去网上找答案,原来方法是这么的多:通过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,和一个字符串格式的图片路径

参考

知乎专栏-web前端开发

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页