前边有提到最近的一个证书生成保存下载打印的需求。
之前实现的是一个单个操作的页面,现在把实现的批量效果和进度效果的代码展示出来。
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=\'width:"+$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", "证书\n"); 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", "证书\n"); 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都是一种解决办法。