最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    正文概述 掘金(acaiEncode)   2021-07-15   653

    贴出本作者处理的具体代码如下:

    /* 判断是否是isIE11或isEdge或isLessIE11 */
    function isIE11Fn() {
        var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
        var isLessIE11 = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1;
        // 判断是否为IE的Edge浏览器
        var isEdge = userAgent.indexOf("Edge") > -1 && !isLessIE11;
        // 判断是否为IE11浏览器
        var isIE11 = userAgent.indexOf("Trident") > -1 && userAgent.indexOf("rv:11.0") > -1;
    
        return isLessIE11 || isIE11 || isEdge;
    };
    // 请求接口,举例子:
    var api = "xxx接口url地址"; // 返回
    if (isLessIE11 || isIE11 || isEdge) {
      api += "&is_base64image=1"; // 返回base64格式图片
    }
    // 请求接口
    jqueryAjaxGet(api, null, function (res) {
        // 里边进行相关的逻辑处理等
        if (res.status == 1) {
            _this.poster = res.data;
            var imgarr = [_this.poster.background_img];
            if(_this.poster.goods_list.length) {
              $.each(_this.poster.goods_list, function(i, item){
                imgarr.push(item.goods_image);
              })
            }
            downloadImg(".poster_con", 'poster', imgarr);
        }
    });
    
    

    一、安装

    script形式引入“html2canvas.min.js”,实际路径按项目的来(记得修改路径~)

    script src="xxx/..../common/html2canvas.min.js"></script>
    

    二、使用

    封装成公共的方法进行使用

    /**
     * @Author: acaiEncode 
     * @File: 保存图片or保存海报
     * @param {*} canvasImgClass  截图的包裹的dom对象(原生)
     * @param {*} imgName 图片名称
     * @param {*} imgArr dom图片数组
     * 提示:前提需要先引入html2canvas.js,版本号:1.0.0-rc.7
     * 使用:downloadImg(".poster_con", 'poster', imgarr);
     */
     function downloadImg(canvasImgClass, imgName, imgArr) {
        loading.showloading();
        var canEle = $(canvasImgClass)[0];   // 获取截图的包裹的dom对象(原生)
        var width = canEle.offsetWidth; // 获取dom宽
        var height = canEle.offsetHeight;   // 获取dom高
        var canvas = document.createElement('canvas');  // 创建一个canvas节点
        // var scale = height / (height * window.devicePixelRatio); // 定义任意放大倍数 支持小数
        var scale = window.devicePixelRatio; // 定义任意放大倍数 支持小数
        canvas.width = width * scale; // 定义canvas 宽度 * 缩放
        canvas.height = height * scale; // 定义canvas高度 *缩放
        var content = canvas.getContext("2d");
        content.scale(scale, scale); //获取context,设置scale 
        // var rect = canEle.getBoundingClientRect(); //获取元素相对于视察的偏移量
        // content.translate(-rect.left, -rect.top); //设置context位置,值为相对于视窗的偏移量负值,让图片复位
        var options = {
            scale: scale, // 添加的scale 参数
            canvas: canvas, // 自定义 canvas
            width: width, // dom 原始宽度
            height: height,
            x: window.pageXOffset, // 裁剪画布X坐标
            y: window.pageYOffset,
            // foreignObjectRendering: true, // 最主要是这句话,官方给出解释是否在浏览器支持的情况下使用ForeignObject渲染,
            // scrollX: 0, // 渲染元素时要使用的x滚动位置(例如,如果Element使用position: fixed)
            // scrollY: 0,
            tainttest: true, // 检测每张图片都已经加载完成
            useCORS: true // 【重要】开启跨域配置
        };
        // 重点:接口图片返回较多时需等图片加载完成才进行截图描绘
        if(imgArr && imgArr.length) {
            var img = [],
            flag = 0,
            mulitImg = imgArr;
            var imgTotal = mulitImg.length;
            for (var i = 0; i < imgTotal; i++) {
                img[i] = new Image()
                img[i].onload = function () {
                    //第i张图片加载完成
                    flag++
                    if (flag == imgTotal) {
                        // 全部加载完成,进行画布的裁剪
                        getCanvas(canvas,canEle,options,imgName)
                    }
                }
                img[i].src = mulitImg[i];
            }
        } else {
            // 画布的裁剪
            getCanvas(canvas,canEle,options,imgName)
        }
    };
    /**
     * 画布生成后下载图片
     *
     * @param {*} canvas 画布
     * @param {*} canEle dom对象
     * @param {*} options 配置项
     * @param {*} imgName 图片名称
     */
    function getCanvas(canvas, canEle, options, imgName) {
        var canvas = canvas;
        html2canvas(canEle,options).then(function(canvas) {
            var context = canvas.getContext('2d');
            // 关闭抗锯齿 保证生成的分享图是清晰的
            context.mozImageSmoothingEnabled = false;
            context.webkitImageSmoothingEnabled = false;
            context.msImageSmoothingEnabled = false;
            context.imageSmoothingEnabled = false;
            var imgDataUrl = canvas
            .toDataURL("image/" + ".jpg")
            .replace("image/" + ".jpg", "image/octet-stream"); // 得到图片base64编码数据
            if (window.navigator.msSaveOrOpenBlob) {
                // 允许用户在客户端上保存文件
                var bstr = atob(imgDataUrl.split(",")[1]);
                var n = bstr.length;
                var u8arr = new Uint8Array(n);
                while (n--) {
                  u8arr[n] = bstr.charCodeAt(n);
                }
                var blob = new Blob([u8arr]);
                window.navigator.msSaveOrOpenBlob(blob, imgName + "." + "jpg");
              } else {
                // 这里就按照chrome等新版浏览器来处理保存图片
                var a = document.createElement("a");
                a.href = imgDataUrl;
                // a.id = 'imgDownBtn';
                a.setAttribute("download", imgName+".jpg");
                a.click();
                $().remove(a);
                // document.remove($('#imgDownBtn'));
              }
              loading.hideloading();
        });
    }
    // loading
    var loading = {
        showloading: function (msg) {
            var hadMask = $("body div").hasClass(".win-mask");
            if (hadMask) {
                $(".win-mask").show();
            } else {
                loading.innerloading(msg);
            }
        },
        hideloading: function () {
            $(".win-mask").remove();
        },
        innerloading: function (msg) {
            var def_msg = "";
            def_msg = msg ? msg : '正在加载中...';
            $("body").append('<div class="win-mask">\
                                  <div class="loading-box">\
                                      <div class="loadings"></div>&nbsp;&nbsp;' + def_msg + '\
                                  </div>\
                              </div>');
        }
    }
    

    具体页面上的详细使用

    // html
    
    <section id="liveShareWin">
      <div class="commonPopup" style="z-index: 999; display: none"></div>
      <div class="commonPopup-container" style="z-index: 8000; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); display: none; margin-left: -500px; margin-top: -296.5px;">
        <div class="commonPopup-header">
          <h3>分享</h3>
          <div class="close-img commonPopup-close-js"></div>
        </div>
        <div class="commonPopup-body">
          <div class="row">
            <div class="col-md-6 leftBox">
              <h4>直播间小程序码</h4>
              <div class="liveCodeImg">
                <img src="" >  
              </div>
              <div>
                <!-- <button class="saaveCodeBtn imgSaveBtn">保存图片</button> -->
                <a class="saveCodeBtn imgSaveBtn" download="直播间小程序码.jpg">保存图片</a>
              </div>
            </div>
            <div class="col-md-6 rightBox">
              <h4>直播间分享海报</h4>
              <div class="posterShare">
                <div class="bannerImg">
                  <img src="" >  
                </div>
                <h6></h6>
                <div class="footerContent row">
                  <div class="col-md-8">
                    <p class="timesBox"></p>
                    <p class="tips">长按识别小程序码,观看直播</p>  
                  </div>
                  <div class="col-md-4">
                    <div class="miniCode">
                      <img src="" >
                    </div>
                  </div>
                </div>
              </div>
              <div>
                <button class="savePosterBtn imgSaveBtn">保存图片</button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
    
    // css
    
    #liveShareWin .row>div {
        text-align: center;
    }
    
    #liveShareWin .row>.rightBox::after {
        content: '';
        display: inline-block;
        border-right: 1px dashed #ccc;
        height: 50%;
        position: absolute;
        top: 94px;
        left: 0;
    }
    
    #liveShareWin h4 {
        font-size: 18px;
        color: #333;
        font-weight: bold;
        padding-top: 40px;
    }
    
    .liveCodeImg {
        width: 180px;
        height: 180px;
        margin: 0 auto;
        margin-top: 40px;
    }
    
    .liveCodeImg>img {
        width: 100%;
        height: 100%;
    }
    #beginnerGuide .openQuliyBtn,
    #liveShareWin .imgSaveBtn {
        display: inline-block;
        width: 160px;
        height: 40px;
        font-size: 16px;
        color: #fff;
        background-color: #fe5043;
        border-radius: 5px;
    }
    
    .saveCodeBtn {
        margin-top: 60px;
        line-height: 40px;
    }
    
    .posterShare {
        width: 300px;
        /* height: 395px; */
        box-shadow: rgba(0, 0, 0, .13) 0px 0px 13px 1px;
        margin: 0 auto;
        margin-top: 20px;
    }
    
    .bannerImg {
        width: 300px;
        height: 240px;
    }
    .bannerImg>img {
        width: 100%;
        height: 100%;
    }
    
    .savePosterBtn {
        margin-top: 30px;
    }
    
    .posterShare h6 {
        margin: 20px 10px;
        font-size: 16px;
        text-align: left;
        height: 40px;    /* 一定要固定高度,火狐和ie浏览器超过省略,但是点点不会出来 */ 
        line-height: 20px;
        word-break: break-all;
        /* white-space: nowrap; */
        overflow: hidden;
        /* text-overflow: ellipsis; */
    }
    .footerContent {
        padding: 20px 10px;
    }
    
    .footerContent>div {
        padding: 0;
    }
    
    .footerContent p {
        text-align: left;
        font-size: 14px;
        padding-top: 20px
    }
    
    .footerContent p.tips {
        font-size: 12px;
        padding-top: 10px
    }
    
    .footerContent p.tips::after {
        content: '';
        display: block;
        width: 12px;
        height: 2px;
        background-color: red;
        margin-top: 5px;
    }
    
    /* .col-md-8 {
        border-right: 1px dashed #fedada;
    } */
    
    .miniCode {
        width: 62px;
        height: 62px;
        margin: 6px auto;
        margin-left: 20px;
    }
    .miniCode>img {
        width: 100%;
        height: 100%;
    }
    
    // js
    var room_mini_code = '';
    var miniCodeArr,
    poseterBannerArr = [];
    $('.liveManage .tbody').on('click', '.shareBtn', function() {
        var room_id = $(this).data('roomid');
        jqueryAjaxPost(api.shareLive, {room_id: room_id}, function (res) {
            miniCodeArr,
            poseterBannerArr  = [];
            if(res.status) {
                var res = res.data;
                miniCodeArr = [res.room_mini_code];
                poseterBannerArr = [res.room_mini_code, res.share_img];
                room_mini_code = res.room_mini_code;
                $('#liveShareWin .liveCodeImg>img').prop('src', res.room_mini_code);
                // $('#liveShareWin .saveCodeBtn').prop('href', res.room_mini_code); // 直播间小程序码
    
                $('#liveShareWin .miniCode>img').prop('src', res.room_mini_code);
                $('#liveShareWin .bannerImg>img').prop('src', res.share_img);
                $('#liveShareWin .posterShare>h6').html(res.name);
                var times = res.start_time + '&nbsp;-&nbsp;' + res.end_time;
                $('#liveShareWin .footerContent .timesBox').html(times);
                liveShareWin.show();
            } else {
                alert(res.msg);
            }
        });
    });
    // 保存图片-download
    $('#liveShareWin .saveCodeBtn').on('click', function() {
        // (-html2canvas实现方式)
    //     downloadImg('#liveShareWin .liveCodeImg', '小程序码', miniCodeArr);
        if(room_mini_code) {
            init.compADown(room_mini_code, '直播间小程序码');
        }
    })
    $('#liveShareWin .savePosterBtn').on('click', function() {
        downloadImg('#liveShareWin .posterShare', '海报', poseterBannerArr);
        // liveShareWin.hide();
    })
    

    效果图:

    使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    三、遇到bug及对策

    1、在jQuery中引入使用html2vanvas.js,在IE浏览器会有出现一个报错:SCRIPT5009: “Promise”未定义

    使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    解决方案:引入es6-promise.auto.min.js插件进行处理。

    2、jQuery配合html2canvas 使用时 报错 Uncaught (in promise) Provided element is not within a Document

    使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    原因是:html2canvas接收的是 一个 js DOM 元素而不是 一个 jQuery DOM对象。

    var canEle = $(canvasImgClass); // jquery 获取元素
    

    解决思路:

    var canEle = $(canvasImgClass)[0];   // 获取截图的包裹的dom对象(原生)
    

    3、使用img = new Image(); img.onload = function() {}后html2canvas出现以下报错:

    使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    配置项加入:

    foreignObjectRendering: true, // 最主要是这句话,官方给出解释是否在浏览器支持的情况下使用ForeignObject渲染,
    

    报错虽然解决,但是出现另外的问题:图片无法显示,绘图错乱。

    使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    经过排查,发现主要原因是:由如下代码导致图片还在onload,而画布还没有开始画,就隐藏了,因此画布就没有高度/宽度,以至于报错,注释后,则没有报错了。

    $("#poster_body").attr("style", "display:none;");
    

    因此得出结论:必须是dom可视才能很好的进行使用html2canvas截图生成海报!

    4、html2canvas对两行省略不识别,会直接丢弃,出来空白的结果;而一行省略的话,点点也是不识别的,会直接切掉文字

    5、html2canvas对虚线无效,会把虚线识别为实线展示出来

    解决方案(本文采用的方案):不用虚线或者改为实线!(一定要使用需要用虚线的客官,可以尝试贴出来解决的方案)。

    6、弹窗使用html2canvas后一直都是空白的!

    原因是:截取区域在弹窗

    解决方案:

    使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    番外:移动端使用html2canvas进行生成海报并下载图片

    1、pc端所使用的方式在移动端在使用时,出现不适配兼容所有移动端的各个浏览器的问题。

    目前qq打开h5页面,则前提需要安装qq浏览器,则可以进行下载,UC等类型的浏览器可以下载;

    微信内置浏览器不兼容,原因其不支持下载文件的原因,要解决此问题。

    具体的解决方案可参考以下:(主要是通过跳转第三方浏览器即可使用)

    (1)微信内置浏览器不支持下载文件应用的解决方法

    (2)微信内置浏览器不支持下载的解决方案 微信点击链接直接下载app安装包功能实现方式

    (3)使用h5 标签 href='url' download 下载踩过的坑

    其次,h5内嵌到自己的app上也有问题:安卓能够进行下载图片,前提是要传生成好的图片过去,但是安卓是不能够下载的,只能长按保存图片!总结如下:

    2、因此鉴于以上所描述的种种问题,若移动端想要实现海报的下载图片功能,又能够友好的兼容移动端端各个端,采用的最佳方案就是把html2canvas生成的海报图片,展示在页面上,引导用户进行长按保存图片。

    效果案例图:

    使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    具体代码参考: [html2canvas在vue2中的应用-移动端](html2canvas在vue2中的应用-移动端 #掘金文章# juejin.cn/post/698387…)


    起源地下载网 » 使用html2canvas、jQuery结合实现PC端绘制canvas图并下载

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元