zoukankan      html  css  js  c++  java
  • js证书批量生成与打包下载

    前边有提到最近的一个证书生成保存下载打印的需求。

    之前实现的是一个单个操作的页面,现在把实现的批量效果和进度效果的代码展示出来。

    html

     1 <button class="btn btn-primary" ng-click="derive()" style="margin-top: 20px;">生成证书(方案1)</button>
     2                     <button class="btn btn-primary" ng-click="derive2()" style="margin-top: 20px;">生成证书(方案2)</button>
     3                     <button class="btn btn-primary" ng-click="derive3()" style="margin-top: 20px;">生成证书(方案3)</button>
     4 <grid-table data-control="tableControl"></grid-table>
     5         <!-- 进度 -->
     6         <div class="progress_cls" ng-if="progressShow">
     7             <div class="layui-progress layui-progress-big" lay-filter="notifierProgress" lay-showpercent="yes">
     8                 <div class="layui-progress-bar" lay-percent="0%">
     9                 <!-- 解决数字不出来问题 -->
    10                     <span class="layui-progress-text">0%</span>
    11                 </div>
    12             </div>
    13             <div class="progress_stitistics_cls">
    14                 <div>总数:<span>{{progressTotal}}</span></div>
    15                 <div>成功:<span>{{doneNum}}</span></div>
    16                 <div>失败:<span>{{failedNum}}</span></div>
    17             </div>
    18             <button class="btn btn-primary" ng-click="closeProgress()" ng-if="progressDone">确定</button>
    19         </div>
    20         <!-- 进度2 -->
    21         <div class="progress_cls" ng-if="progressShow2">
    22             <div class="layui-progress layui-progress-big" lay-filter="notifierProgress2" lay-showpercent="yes">
    23                 <div class="layui-progress-bar" lay-percent="0%">
    24                 <!-- 解决数字不出来问题 -->
    25                     <span class="layui-progress-text">0%</span>
    26                 </div>
    27             </div>
    28             <div class="progress_stitistics_cls">
    29                 <div>总数:<span>{{progressTotal}}</span></div>
    30                 <div>当前完成:<span>{{doneNum}}</span></div>
    31             </div>
    32             <button class="btn btn-primary" ng-click="closeProgress()" ng-if="progressDone2">确定</button>
    33         </div>
    34         <!-- 进度3 -->
    35         <div class="progress_cls" ng-if="progressShow3">
    36             <div class="layui-progress layui-progress-big" lay-filter="notifierProgress3" lay-showpercent="yes">
    37                 <div class="layui-progress-bar" lay-percent="0%">
    38                 <!-- 解决数字不出来问题 -->
    39                     <span class="layui-progress-text">0%</span>
    40                 </div>
    41             </div>
    42             <div class="progress_stitistics_cls">
    43                 <div>总数:<span>{{progressTotal}}</span></div>
    44                 <div>当前完成:<span>{{doneNum}}</span></div>
    45             </div>
    46             <button class="btn btn-primary" ng-click="closeProgress()" ng-if="progressDone3">确定</button>
    47         </div>

    css

     1 #toPrint {
     2     position:absolute;
     3     left: 10000px;
     4     top: 50%;
     5 }
     6 
     7 #toPrint div {
     8     position:absolute;
     9     font-weight: bold;
    10 }
    11 
    12 #toPrint img {
    13     position:absolute;
    14 }
    15 
    16 #textArea {
    17     width: 100%;
    18     height: 100%;
    19 }
    20 
    21 .printCanvas {
    22     display:inline-block;
    23 }
    24 
    25 #toPrint3 {
    26     position:absolute;
    27     left: 10000px;
    28     top: 50%;
    29     display: inline-flex;
    30 }

    js

      1  /*
      2      导出数据
      3      */
      4     $scope.derive = function () {
      5         var toSendList = [];
      6         var passList = [];
      7         for(var i=0;i<$scope.tableControl.rows.length;i++) {
      8             if($scope.tableControl.rows[i].select) {
      9                 toSendList.push($scope.tableControl.allData[i]);
     10                 //没有数据,原5,现先1
     11                 if(1 == $scope.tableControl.allData[i].applyStatus) {
     12                     passList.push($scope.tableControl.allData[i]);
     13                 }
     14             }
     15         }
     16         if(1 > toSendList.length) {
     17             layer.alert("请选择需要生成证书的记录");
     18             return;
     19         }
     20         if(toSendList.length != passList.length) {
     21             layer.alert("只能对审核通过的记录进行证书生成");
     22             return;
     23         }
     24         layer.confirm("是否确认生成证书?", {
     25             btn: ['确定', '取消'] 
     26         }, function () {
     27             $scope.progressTotal = toSendList.length;
     28             $scope.doneNum = 0;
     29             $scope.failedNum = 0;
     30 
     31             layer.closeAll();
     32             var maskLoad = layer.load(1, {shade: [0.8, '#393D49']});
     33             //打开进度
     34             $scope.curProgress = "0%";
     35             $scope.progressShow = true;
     36             $.each(toSendList, function(index, e){
     37                 var url = location.origin+"/pages/print/printBatch.html?"+encodeURIComponent(e.studentName)+"&&"+encodeURIComponent(e.applySchoolName);
     38                 //services.save_notifier(url).success(function (res) {
     39                 $.ajax({
     40                     url: location.origin+'/basic/school',
     41                     headers: {'token': $rootScope.token},
     42                     type: 'get',
     43                     dataType: 'json',
     44                     contentType: 'application/json;charset=UTF-8',
     45                     async: true,
     46                 }).success(function (res) {
     47                     if ('OK' == res.result) {
     48                         $scope.doneNum++;
     49                     } else {
     50                         $scope.failedNum++;
     51                     }
     52                 }).error(function (res) {
     53                     $scope.failedNum++;
     54                 }).always(function () {
     55                     //刷新成功和失败数量
     56                     if(($scope.doneNum + $scope.failedNum) < $scope.progressTotal) {
     57                         //更新进度
     58                         //$scope.curProgress = Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%";
     59                         element.progress('notifierProgress', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")
     60                     } else {
     61                         //完成
     62                         $scope.curProgress = "100%";
     63                         ////进度条渲染需要时间??数据较少时执行完成还没渲染出来--改用定时器
     64                         var finishInterval = setInterval(function() {
     65                             if($(".layui-progress")[0]) {
     66                                 element.progress('notifierProgress', "100%");
     67                                 clearInterval(finishInterval);
     68                             }
     69                         }, 200);
     70                         $scope.progressDone = true;
     71                         //去掉转圈
     72                         $(".layui-layer-loading").hide();
     73                         //layer.closeAll();
     74                     }
     75                 });
     76             });
     77             
     78         });
     79     }
     80     
     81     //方案2
     82     $scope.derive2 = function () {
     83         //先单线程
     84         var toSendList = [];
     85         var passList = [];
     86         for(var i=0;i<$scope.tableControl.rows.length;i++) {
     87             if($scope.tableControl.rows[i].select) {
     88                 toSendList.push($scope.tableControl.allData[i]);
     89                 //没有数据,原5,现先1
     90                 if(1 == $scope.tableControl.allData[i].applyStatus) {
     91                     passList.push($scope.tableControl.allData[i]);
     92                 }
     93             }
     94         }
     95         if(1 > toSendList.length) {
     96             layer.alert("请选择需要生成证书的记录");
     97             return;
     98         }
     99         if(toSendList.length != passList.length) {
    100             layer.alert("只能对审核通过的记录进行证书生成");
    101             return;
    102         }
    103         layer.confirm("是否确认生成证书?", {
    104             btn: ['确定', '取消'] 
    105         }, function () {
    106             $scope.progressTotal = toSendList.length;
    107             $scope.doneNum = 0;
    108             $scope.failedNum = 0;
    109 
    110             layer.closeAll();
    111             var maskLoad = layer.load(1, {shade: [0.8, '#393D49']});
    112             //打开进度
    113             $scope.curProgress = "0%";
    114             $scope.progressShow2 = true;
    115             
    116             //弹出隐藏绘图层
    117             $("#printArea").remove();
    118             $("body").append("<div id='printArea'><div id='toPrint'></div></div>");
    119             
    120             //绘制证书
    121             suitScreen($scope);
    122             var imgStr = "<img src='" + $scope.printObj.notifierObj.url+"' style='"+$scope.printObj.notifierObj.width+"px;height:"+
    123             $scope.printObj.notifierObj.height+"px'><div id='textArea'></div>";
    124             $("#toPrint").append(imgStr);
    125             $("#toPrint").css("margin-top", (0-$scope.printObj.notifierObj.height-60)/2+"px");
    126             $("#toPrint").css("height", $scope.printObj.notifierObj.height+"px");
    127             $("#toPrint").css("width", $scope.printObj.notifierObj.width+"px");
    128             
    129             //填充文字
    130             $.each(toSendList, function(index, e){
    131                 $("#textArea").empty();
    132                 $scope.printObj.paramList[0].objName = e.studentName;
    133                 $scope.printObj.paramList[1].objName = e.applySchoolName;
    134                 var htmlStr = "";
    135                 for(i=0;i<$scope.printObj.paramList.length;i++) {
    136                     var nowObj = $scope.printObj.paramList[i];
    137                     if(nowObj.fontSize < 12) {
    138                         htmlStr += "<div style='font-family:"+nowObj.fontFamily+";font-size:"+nowObj.fontSize+"px;top:"+nowObj.top+"px;left:"+nowObj.left+
    139                         //谷歌浏览器字体小于12px时会不再变小,使用-webkit-transform兼容,并设置已左上角作为变换原点
    140                             "px;-webkit-transform:scale("+nowObj.fontSize/12+","+nowObj.fontSize/12+");transform-origin:0 0'>"+nowObj.objName+"</div>";
    141                     } else {
    142                         htmlStr += "<div style='font-family:"+nowObj.fontFamily+";font-size:"+nowObj.fontSize+"px;top:"+nowObj.top+"px;left:"+nowObj.left+
    143                             "px'>"+nowObj.objName+"</div>";
    144                     }
    145                 }
    146                 //$("#toPrint").css("margin-left", (0-$scope.printObj.notifierObj.width)/2+"px");
    147                 $("#textArea").append(htmlStr);
    148                 
    149                 //保存
    150                 html2canvas(document.querySelector("#toPrint")).then(function(canvas) {
    151                     var type = 'png';//格式可以自定义
    152                     var imgData = canvas.toDataURL(type);
    153                     imgData = imgData.replace(_fixType(type),'image/octet-stream');
    154                     //文件名可以自定义
    155                     var filename = '录取通知书_' + e.studentName + '.' + type;
    156                     saveFile(imgData,filename);
    157                     $scope.doneNum++;
    158                     //刷新成功和失败数量
    159                     if(($scope.doneNum + $scope.failedNum) < $scope.progressTotal) {
    160                         //更新进度
    161                         //$scope.curProgress = Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%";
    162                         element.progress('notifierProgress2', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")
    163                     } else {
    164                         //完成
    165                         $scope.curProgress = "100%";
    166                         ////进度条渲染需要时间??数据较少时执行完成还没渲染出来--改用定时器
    167                         var finishInterval = setInterval(function() {
    168                             if($(".layui-progress")[0]) {
    169                                 element.progress('notifierProgress2', "100%");
    170                                 clearInterval(finishInterval);
    171                             }
    172                         }, 200);
    173                         $scope.progressDone2 = true;
    174                         //去掉转圈
    175                         $(".layui-layer-loading").hide();
    176                     }
    177                 });
    178             });
    179             
    180         });
    181     }
    182     
    183     //方案3
    184     $scope.derive3 = function () {
    185         //先单线程
    186         var toSendList = [];
    187         var passList = [];
    188         for(var i=0;i<$scope.tableControl.rows.length;i++) {
    189             if($scope.tableControl.rows[i].select) {
    190                 toSendList.push($scope.tableControl.allData[i]);
    191                 //没有数据,原5,现先1
    192                 if(1 == $scope.tableControl.allData[i].applyStatus) {
    193                     passList.push($scope.tableControl.allData[i]);
    194                 }
    195             }
    196         }
    197         if(1 > toSendList.length) {
    198             layer.alert("请选择需要生成证书的记录");
    199             return;
    200         }
    201         if(toSendList.length != passList.length) {
    202             layer.alert("只能对审核通过的记录进行证书生成");
    203             return;
    204         }
    205         layer.confirm("是否确认生成证书?", {
    206             btn: ['确定', '取消'] 
    207         }, function () {
    208             $scope.progressTotal = toSendList.length;
    209             $scope.doneNum = 0;
    210             $scope.failedNum = 0;
    211 
    212             layer.closeAll();
    213             var maskLoad = layer.load(1, {shade: [0.8, '#393D49']});
    214             //打开进度
    215             $scope.curProgress = "0%";
    216             $scope.progressShow3 = true;
    217             
    218             //弹出隐藏绘图层
    219             $("#toPrint3").remove();
    220             $("body").append("<div id='toPrint3'></div>");
    221             
    222             suitScreen($scope);
    223 
    224             var allCanvas = $("canvas");
    225             var zip = new JSZip();
    226             //zip.file("readme.txt", "证书
    ");
    227             var img = zip.folder("images");
    228 
    229             //图片加载是异步,所有用递归来做,否则前边生成的都会被最后一个覆盖
    230             (function loop(n) {
    231                 if (n>=toSendList.length) return;
    232                 
    233                 var image = new Image();
    234                 image.src = $scope.printObj.notifierObj.url;
    235                 image.onload = function () { //为异步函数,所以将创建canvas放在onload中.
    236 
    237                     $("#toPrint3").empty();
    238                     $("#toPrint3").append("<canvas id='toPrint_' class='printCanvas'></canvas>");
    239                     $scope.printObj.paramList[0].objName = toSendList[n].studentName;
    240                     $scope.printObj.paramList[1].objName = toSendList[n].applySchoolName;
    241                     
    242                     
    243                     $("#toPrint_").css("margin-top", (0-$scope.printObj.notifierObj.height)/2+"px");
    244                     var canvas = document.getElementById("toPrint_");
    245                     canvas.width = $scope.printObj.notifierObj.width;
    246                     canvas.height = $scope.printObj.notifierObj.height;
    247                     var ctx = canvas.getContext("2d");
    248                     ctx.drawImage(image, 0, 0, $scope.printObj.notifierObj.width, $scope.printObj.notifierObj.height);
    249                     $.each($scope.printObj.paramList, function(index, e) {
    250                         //canvas的字体不会有12px的兼容性问题
    251                         ctx.font = "bold "+e.fontSize+"px "+e.fontFamily;
    252                         //canvas写字以字体的左下角为基准,因而要再加一个字体大小的高度
    253                         ctx.fillText(e.objName, e.left, e.top+e.fontSize);
    254                     });
    255                     img.file('录取通知书_' + toSendList[n].studentName + '.png', canvas.toDataURL().substring(22), {base64: true});
    256                     $scope.doneNum++;
    257                     //刷新成功和失败数量
    258                     if(($scope.doneNum + $scope.failedNum) < $scope.progressTotal) {
    259                         //更新进度
    260                         //$scope.curProgress = Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%";
    261                         element.progress('notifierProgress3', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")
    262                     } else {
    263                         //完成
    264                         $scope.curProgress = "100%";
    265                         var finishInterval = setInterval(function() {
    266                             if($(".layui-progress")[0]) {
    267                                 element.progress('notifierProgress3', "100%");
    268                                 clearInterval(finishInterval);
    269                             }
    270                         }, 200);
    271                         $scope.progressDone3 = true;
    272                         //去掉转圈
    273                         $(".layui-layer-loading").hide();
    274                         
    275                         zip.generateAsync({type:"blob"}).then(function(content) {
    276                             saveAs(content, "证书.zip");
    277                         });
    278                     }
    279                     
    280                     loop(n+1);
    281                 }
    282           })(0);
    283 
    284 
    285         });
    286     }
    287     
    288     $scope.closeProgress = function () {
    289         $scope.progressShow = false;
    290         $scope.progressDone = false;
    291         $scope.progressShow2 = false;
    292         $scope.progressDone2 = false;
    293         $scope.progressShow3 = false;
    294         $scope.progressDone3 = false;
    295         layer.closeAll();
    296     }
    297     
    298   //模板
    299     $scope.printObj = {
    300         notifierObj:{
    301             "url": "/res/img/notifications.png",
    302             "height": "631",
    303             "width": "942"
    304         },
    305         paramList:[{
    306                 "objName":"黄大明",
    307                 "left":"133",
    308                 "top":"191",
    309                 "fontSize": "28",
    310                 "fontFamily": "KaiTi"
    311             },{
    312                 "objName":"SXXX小学",
    313                 "left":"460",
    314                 "top":"272",
    315                 "fontSize": "28",
    316                 "fontFamily": "KaiTi"
    317             },{
    318                 "objName":"2018",
    319                 "left":"195",
    320                 "top":"312",
    321                 "fontSize": "28",
    322                 "fontFamily": "KaiTi"
    323             },{
    324                 "objName":"8",
    325                 "left":"325",
    326                 "top":"312",
    327                 "fontSize": "28",
    328                 "fontFamily": "KaiTi"
    329             },{
    330                 "objName":"31",
    331                 "left":"405",
    332                 "top":"312",
    333                 "fontSize": "28",
    334                 "fontFamily": "KaiTi"
    335             }]
    336     }
    337     
    338     function suitScreen($scope) {
    339         //A4横向标准
    340         var effectiveHeight = 1240;
    341         var effectiveWidth = 1754;
    342         if($scope.printObj.notifierObj.width/effectiveWidth > $scope.printObj.notifierObj.height/effectiveHeight) {
    343             //取最接近的一个属性进行自适应,并适当调小一些
    344             var suitTimes = $scope.printObj.notifierObj.width/effectiveWidth*1.2;
    345         } else {
    346             var suitTimes = $scope.printObj.notifierObj.height/effectiveHeight*1.2;
    347         }
    348         $scope.printObj.notifierObj.width = $scope.printObj.notifierObj.width/suitTimes;
    349         $scope.printObj.notifierObj.height = $scope.printObj.notifierObj.height/suitTimes;
    350         for(i=0;i<$scope.printObj.paramList.length;i++) {
    351             $scope.printObj.paramList[i].fontSize = $scope.printObj.paramList[i].fontSize/suitTimes;
    352             $scope.printObj.paramList[i].left = $scope.printObj.paramList[i].left/suitTimes;
    353             $scope.printObj.paramList[i].top = $scope.printObj.paramList[i].top/suitTimes;
    354         }
    355     }
    356     
    357     function _fixType(type) {
    358         //imgData是一串string,base64
    359         type = type.toLowerCase().replace(/jpg/i, 'jpeg');
    360         var r = type.match(/png|jpeg|bmp|gif/)[0];
    361         return 'image/' + r;
    362     }
    363 
    364     function saveFile(data, filename) {
    365         var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
    366         save_link.href = data;
    367         save_link.download = filename;
    368        
    369         //下载
    370         var event = document.createEvent('MouseEvents');
    371         event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    372         save_link.dispatchEvent(event);
    373     }
    374     
    375     //方案3使用canvas先画好,然后批量打包保存
    376     function drawNotifier($scope, id, img) {
    377         //canvas需要先定位好,否则画好再动就清除了
    378         //$("#toPrint").css("margin-left", (0-$scope.printObj.notifierObj.width)/2+"px");不可见元素,同样不考虑其左右缩进
    379         $(id).css("margin-top", (0-$scope.printObj.notifierObj.height)/2+"px");
    380         var canvas = document.getElementById(id.substring(1));
    381         canvas.width = $scope.printObj.notifierObj.width;
    382         canvas.height = $scope.printObj.notifierObj.height;
    383         var ctx = canvas.getContext("2d");
    384         var img=new Image();
    385         img.src = $scope.printObj.notifierObj.url;
    386         var deferred=$.Deferred();
    387         var thisObj = $scope.printObj;
    388         //img.onload=function() {
    389         requestAnimationFrame(function() {
    390             //需要onload方法接收,否则画不出
    391             ctx.drawImage(img, 0, 0, thisObj.notifierObj.width, thisObj.notifierObj.height);
    392             //写文字,且要在画好图片之后写,否则会被图片覆盖
    393             $.each(thisObj.paramList, function(index, e) {
    394                 //canvas的字体不会有12px的兼容性问题
    395                 ctx.font = "bold "+e.fontSize+"px "+e.fontFamily;
    396                 //canvas写字以字体的左下角为基准,因而要再加一个字体大小的高度
    397                 ctx.fillText(e.objName, e.left, e.top+e.fontSize);
    398             });
    399             deferred.resolve(canvas.toDataURL().substring(22));
    400         })
    401         //}
    402         return deferred.promise();
    403         
    404     }

    以上是三种实现方案,第一种需要一个接口,后两种不需要接口,直接前端生成。

    说一下中间遇到的问题:

    1.进度条里边的文字显示不出来:

    用的是layui的进度条,很简单,就几行代码。

    <div class="layui-progress layui-progress-big" lay-filter="notifierProgress" lay-showpercent="yes">
            <div class="layui-progress-bar" lay-percent="0%">
            </div>
    </div>

    但是进度百分比文字就是显示不出来,查看元素,官方api里是有span标签的,但是自己的一直没有,可见layui官网也是有点坑。也许一些版本或者新的版本支持吧,但是有个直接有效的解决办法就是,在内部直接写一个span标签。

          <div class="layui-progress layui-progress-big" lay-filter="notifierProgress" lay-showpercent="yes">
                    <div class="layui-progress-bar" lay-percent="0%">
                    <!-- 解决数字不出来问题 -->
                        <span class="layui-progress-text">0%</span>
                    </div>
                </div>

    2.进度动态更新:

    当前使用的是angular框架,我使用了一个变量来动态刷新,但是实际并没有效果。最终不得不使用组件的方法:

    element.progress('notifierProgress', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")

    其中第一个参数就是前边的lay-filter

    3.对于需要进行绘制又不想让用户看到:

    很简单的方法,直接给你需要操作的元素绝对定位,然后给他一个很大很大的left(当然上下左右都可以),这样他就飘到屏幕的十万八千里外了,用户除非自己F12看,否则永远也看不到。这个方法之前在上一家公司有使用过。

    4.对于canvas画图片异步加载的问题:

    这个问题困扰了我很久,因为我要做批量绘制,使用同一个dom,绘制完一个然后清空再绘制下一个。早早就写完了逻辑,一运行也没有报错,燃鹅,打开文件一看,全都是最后一条数据生成的图片。已经使用了image.onload进行绘制了还出现这种问题。然后打断点调试,发现each遍历完了,才走进onload事件。我就又尝试着用定时器、用回调,都没有成功,而且这样比较容易出现问题。最终找到了一个解决办法,那就是用递归。代码如下

     1 //图片加载是异步,所有用递归来做,否则前边生成的都会被最后一个覆盖
     2             (function loop(n) {
     3                 if (n>=toSendList.length) return;
     4                 
     5                 var image = new Image();
     6                 image.src = $scope.printObj.notifierObj.url;
     7                 image.onload = function () { //为异步函数,所以将创建canvas放在onload中.
     8 
     9                     $("#toPrint3").empty();
    10                     $("#toPrint3").append("<canvas id='toPrint_' class='printCanvas'></canvas>");
    11                     $scope.printObj.paramList[0].objName = toSendList[n].studentName;
    12                     $scope.printObj.paramList[1].objName = toSendList[n].applySchoolName;
    13                     
    14                     
    15                     $("#toPrint_").css("margin-top", (0-$scope.printObj.notifierObj.height)/2+"px");
    16                     var canvas = document.getElementById("toPrint_");
    17                     canvas.width = $scope.printObj.notifierObj.width;
    18                     canvas.height = $scope.printObj.notifierObj.height;
    19                     var ctx = canvas.getContext("2d");
    20                     ctx.drawImage(image, 0, 0, $scope.printObj.notifierObj.width, $scope.printObj.notifierObj.height);
    21                     $.each($scope.printObj.paramList, function(index, e) {
    22                         //canvas的字体不会有12px的兼容性问题
    23                         ctx.font = "bold "+e.fontSize+"px "+e.fontFamily;
    24                         //canvas写字以字体的左下角为基准,因而要再加一个字体大小的高度
    25                         ctx.fillText(e.objName, e.left, e.top+e.fontSize);
    26                     });
    27                     img.file('录取通知书_' + toSendList[n].studentName + '.png', canvas.toDataURL().substring(22), {base64: true});
    28                     $scope.doneNum++;
    29                     //刷新成功和失败数量
    30                     if(($scope.doneNum + $scope.failedNum) < $scope.progressTotal) {
    31                         //更新进度
    32                         //$scope.curProgress = Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%";
    33                         element.progress('notifierProgress3', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")
    34                     } else {
    35                         //完成
    36                         $scope.curProgress = "100%";
    37                         var finishInterval = setInterval(function() {
    38                             if($(".layui-progress")[0]) {
    39                                 element.progress('notifierProgress3', "100%");
    40                                 clearInterval(finishInterval);
    41                             }
    42                         }, 200);
    43                         $scope.progressDone3 = true;
    44                         //去掉转圈
    45                         $(".layui-layer-loading").hide();
    46                         
    47                         zip.generateAsync({type:"blob"}).then(function(content) {
    48                             saveAs(content, "证书.zip");
    49                         });
    50                     }
    51                     
    52                     loop(n+1);
    53                 }
    54           })(0);

    还有在调试中使用的一些方法,其中:

     1 var deferred=$.Deferred();
     2         var thisObj = $scope.printObj;
     3         //img.onload=function() {
     4         requestAnimationFrame(function() {
     5             //需要onload方法接收,否则画不出
     6             ctx.drawImage(img, 0, 0, thisObj.notifierObj.width, thisObj.notifierObj.height);
     7             //写文字,且要在画好图片之后写,否则会被图片覆盖
     8             $.each(thisObj.paramList, function(index, e) {
     9                 //canvas的字体不会有12px的兼容性问题
    10                 ctx.font = "bold "+e.fontSize+"px "+e.fontFamily;
    11                 //canvas写字以字体的左下角为基准,因而要再加一个字体大小的高度
    12                 ctx.fillText(e.objName, e.left, e.top+e.fontSize);
    13             });
    14             deferred.resolve(canvas.toDataURL().substring(22));
    15         })
    16         //}
    17         return deferred.promise();

    给方法添加回调,使用promise,这样在调用这个方法时就可以用then进行接收了。

    requestAnimationFrame,一个用的好比较有意思的window方法,类似timeout和interval,但是不需要设置时间,此处可以代替onload使用。

    5.canvas转base64与文件操作:

     1 //canvas转图片
     2 
     3 canvas.toDataURL().substring(22)
     4 
     5 //js新建文件和文件填充
     6 
     7 var zip = new JSZip();
     8 //zip.file("readme.txt", "证书
    ");
     9 var img = zip.folder("images");
    10 
    11 img.file('录取通知书_' + toSendList[n].studentName + '.png', canvas.toDataURL().substring(22), {base64: true});
    12 
    13 //js文件打包下载
    14 
    15 zip.generateAsync({type:"blob"}).then(function(content) {
    16 saveAs(content, "证书.zip");
    17 });

    用到的插件:FileSaver.js, jszip.min.js。用法也比较简单。

    6.数据较少时,进度条无法刷新到100%的问题:

    数据较少,用时较少,然后进度条渲染出来了,但是一直停在0%。没有研究源码,不知道是因为异步加载的问题还是因为css动画的样式问题还是因为渲染组件异步的问题,总之就是在执行完之后,打断点审查元素并没有生成组件,所有此时更新进度100%也没用。

    解决方法:使用定时器

    1     var finishInterval = setInterval(function() {
    2           if($(".layui-progress")[0]) {
    3                   element.progress('notifierProgress3', "100%");
    4                        clearInterval(finishInterval);
    5            }
    6      }, 200);

    一般遇到这种异步造成还没渲染完成就做了处理的问题,使用定时器或者timeout都是一种解决办法。

    FIGHTING
  • 相关阅读:
    VMware的三种网络连接方式区别
    迁移至博客园
    Oracle常用语句集合
    Oracle表的几种连接方式
    Oracle逻辑结构(TableSpace→Segment→Extent→Block)
    从线性代数的角度理解线性时不变系统和信号响应
    从线性代数的角度理解傅里叶变换
    在WPF中调用文件夹浏览/选择对话框
    在WPF中调用打开文件对话框
    在WPF中调用另存为对话框
  • 原文地址:https://www.cnblogs.com/ljwsyt/p/9555931.html
Copyright © 2011-2022 走看看