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

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

html

 <button class="btn btn-primary" ng-click="derive()" style="margin-top: 20px;">生成证书(方案1)</button>
<button class="btn btn-primary" ng-click="derive2()" style="margin-top: 20px;">生成证书(方案2)</button>
<button class="btn btn-primary" ng-click="derive3()" style="margin-top: 20px;">生成证书(方案3)</button>
<grid-table data-control="tableControl"></grid-table>
<!-- 进度 -->
<div class="progress_cls" ng-if="progressShow">
<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>
<div class="progress_stitistics_cls">
<div>总数:<span>{{progressTotal}}</span></div>
<div>成功:<span>{{doneNum}}</span></div>
<div>失败:<span>{{failedNum}}</span></div>
</div>
<button class="btn btn-primary" ng-click="closeProgress()" ng-if="progressDone">确定</button>
</div>
<!-- 进度2 -->
<div class="progress_cls" ng-if="progressShow2">
<div class="layui-progress layui-progress-big" lay-filter="notifierProgress2" lay-showpercent="yes">
<div class="layui-progress-bar" lay-percent="0%">
<!-- 解决数字不出来问题 -->
<span class="layui-progress-text">0%</span>
</div>
</div>
<div class="progress_stitistics_cls">
<div>总数:<span>{{progressTotal}}</span></div>
<div>当前完成:<span>{{doneNum}}</span></div>
</div>
<button class="btn btn-primary" ng-click="closeProgress()" ng-if="progressDone2">确定</button>
</div>
<!-- 进度3 -->
<div class="progress_cls" ng-if="progressShow3">
<div class="layui-progress layui-progress-big" lay-filter="notifierProgress3" lay-showpercent="yes">
<div class="layui-progress-bar" lay-percent="0%">
<!-- 解决数字不出来问题 -->
<span class="layui-progress-text">0%</span>
</div>
</div>
<div class="progress_stitistics_cls">
<div>总数:<span>{{progressTotal}}</span></div>
<div>当前完成:<span>{{doneNum}}</span></div>
</div>
<button class="btn btn-primary" ng-click="closeProgress()" ng-if="progressDone3">确定</button>
</div>

css

 #toPrint {
position:absolute;
left: 10000px;
top: 50%;
} #toPrint div {
position:absolute;
font-weight: bold;
} #toPrint img {
position:absolute;
} #textArea {
width: 100%;
height: 100%;
} .printCanvas {
display:inline-block;
} #toPrint3 {
position:absolute;
left: 10000px;
top: 50%;
display: inline-flex;
}

js

  /*
导出数据
*/
$scope.derive = function () {
var toSendList = [];
var passList = [];
for(var i=0;i<$scope.tableControl.rows.length;i++) {
if($scope.tableControl.rows[i].select) {
toSendList.push($scope.tableControl.allData[i]);
//没有数据,原5,现先1
if(1 == $scope.tableControl.allData[i].applyStatus) {
passList.push($scope.tableControl.allData[i]);
}
}
}
if(1 > toSendList.length) {
layer.alert("请选择需要生成证书的记录");
return;
}
if(toSendList.length != passList.length) {
layer.alert("只能对审核通过的记录进行证书生成");
return;
}
layer.confirm("是否确认生成证书?", {
btn: ['确定', '取消']
}, function () {
$scope.progressTotal = toSendList.length;
$scope.doneNum = 0;
$scope.failedNum = 0; layer.closeAll();
var maskLoad = layer.load(1, {shade: [0.8, '#393D49']});
//打开进度
$scope.curProgress = "0%";
$scope.progressShow = true;
$.each(toSendList, function(index, e){
var url = location.origin+"/pages/print/printBatch.html?"+encodeURIComponent(e.studentName)+"&&"+encodeURIComponent(e.applySchoolName);
//services.save_notifier(url).success(function (res) {
$.ajax({
url: location.origin+'/basic/school',
headers: {'token': $rootScope.token},
type: 'get',
dataType: 'json',
contentType: 'application/json;charset=UTF-8',
async: true,
}).success(function (res) {
if ('OK' == res.result) {
$scope.doneNum++;
} else {
$scope.failedNum++;
}
}).error(function (res) {
$scope.failedNum++;
}).always(function () {
//刷新成功和失败数量
if(($scope.doneNum + $scope.failedNum) < $scope.progressTotal) {
//更新进度
//$scope.curProgress = Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%";
element.progress('notifierProgress', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")
} else {
//完成
$scope.curProgress = "100%";
////进度条渲染需要时间??数据较少时执行完成还没渲染出来--改用定时器
var finishInterval = setInterval(function() {
if($(".layui-progress")[0]) {
element.progress('notifierProgress', "100%");
clearInterval(finishInterval);
}
}, 200);
$scope.progressDone = true;
//去掉转圈
$(".layui-layer-loading").hide();
//layer.closeAll();
}
});
}); });
} //方案2
$scope.derive2 = function () {
//先单线程
var toSendList = [];
var passList = [];
for(var i=0;i<$scope.tableControl.rows.length;i++) {
if($scope.tableControl.rows[i].select) {
toSendList.push($scope.tableControl.allData[i]);
//没有数据,原5,现先1
if(1 == $scope.tableControl.allData[i].applyStatus) {
passList.push($scope.tableControl.allData[i]);
}
}
}
if(1 > toSendList.length) {
layer.alert("请选择需要生成证书的记录");
return;
}
if(toSendList.length != passList.length) {
layer.alert("只能对审核通过的记录进行证书生成");
return;
}
layer.confirm("是否确认生成证书?", {
btn: ['确定', '取消']
}, function () {
$scope.progressTotal = toSendList.length;
$scope.doneNum = 0;
$scope.failedNum = 0; layer.closeAll();
var maskLoad = layer.load(1, {shade: [0.8, '#393D49']});
//打开进度
$scope.curProgress = "0%";
$scope.progressShow2 = true; //弹出隐藏绘图层
$("#printArea").remove();
$("body").append("<div id='printArea'><div id='toPrint'></div></div>"); //绘制证书
suitScreen($scope);
var imgStr = "<img src='" + $scope.printObj.notifierObj.url+"' style='width:"+$scope.printObj.notifierObj.width+"px;height:"+
$scope.printObj.notifierObj.height+"px'><div id='textArea'></div>";
$("#toPrint").append(imgStr);
$("#toPrint").css("margin-top", (0-$scope.printObj.notifierObj.height-60)/2+"px");
$("#toPrint").css("height", $scope.printObj.notifierObj.height+"px");
$("#toPrint").css("width", $scope.printObj.notifierObj.width+"px"); //填充文字
$.each(toSendList, function(index, e){
$("#textArea").empty();
$scope.printObj.paramList[0].objName = e.studentName;
$scope.printObj.paramList[1].objName = e.applySchoolName;
var htmlStr = "";
for(i=0;i<$scope.printObj.paramList.length;i++) {
var nowObj = $scope.printObj.paramList[i];
if(nowObj.fontSize < 12) {
htmlStr += "<div style='font-family:"+nowObj.fontFamily+";font-size:"+nowObj.fontSize+"px;top:"+nowObj.top+"px;left:"+nowObj.left+
//谷歌浏览器字体小于12px时会不再变小,使用-webkit-transform兼容,并设置已左上角作为变换原点
"px;-webkit-transform:scale("+nowObj.fontSize/12+","+nowObj.fontSize/12+");transform-origin:0 0'>"+nowObj.objName+"</div>";
} else {
htmlStr += "<div style='font-family:"+nowObj.fontFamily+";font-size:"+nowObj.fontSize+"px;top:"+nowObj.top+"px;left:"+nowObj.left+
"px'>"+nowObj.objName+"</div>";
}
}
//$("#toPrint").css("margin-left", (0-$scope.printObj.notifierObj.width)/2+"px");
$("#textArea").append(htmlStr); //保存
html2canvas(document.querySelector("#toPrint")).then(function(canvas) {
var type = 'png';//格式可以自定义
var imgData = canvas.toDataURL(type);
imgData = imgData.replace(_fixType(type),'image/octet-stream');
//文件名可以自定义
var filename = '录取通知书_' + e.studentName + '.' + type;
saveFile(imgData,filename);
$scope.doneNum++;
//刷新成功和失败数量
if(($scope.doneNum + $scope.failedNum) < $scope.progressTotal) {
//更新进度
//$scope.curProgress = Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%";
element.progress('notifierProgress2', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")
} else {
//完成
$scope.curProgress = "100%";
////进度条渲染需要时间??数据较少时执行完成还没渲染出来--改用定时器
var finishInterval = setInterval(function() {
if($(".layui-progress")[0]) {
element.progress('notifierProgress2', "100%");
clearInterval(finishInterval);
}
}, 200);
$scope.progressDone2 = true;
//去掉转圈
$(".layui-layer-loading").hide();
}
});
}); });
} //方案3
$scope.derive3 = function () {
//先单线程
var toSendList = [];
var passList = [];
for(var i=0;i<$scope.tableControl.rows.length;i++) {
if($scope.tableControl.rows[i].select) {
toSendList.push($scope.tableControl.allData[i]);
//没有数据,原5,现先1
if(1 == $scope.tableControl.allData[i].applyStatus) {
passList.push($scope.tableControl.allData[i]);
}
}
}
if(1 > toSendList.length) {
layer.alert("请选择需要生成证书的记录");
return;
}
if(toSendList.length != passList.length) {
layer.alert("只能对审核通过的记录进行证书生成");
return;
}
layer.confirm("是否确认生成证书?", {
btn: ['确定', '取消']
}, function () {
$scope.progressTotal = toSendList.length;
$scope.doneNum = 0;
$scope.failedNum = 0; layer.closeAll();
var maskLoad = layer.load(1, {shade: [0.8, '#393D49']});
//打开进度
$scope.curProgress = "0%";
$scope.progressShow3 = true; //弹出隐藏绘图层
$("#toPrint3").remove();
$("body").append("<div id='toPrint3'></div>"); suitScreen($scope); var allCanvas = $("canvas");
var zip = new JSZip();
//zip.file("readme.txt", "证书\n");
var img = zip.folder("images"); //图片加载是异步,所有用递归来做,否则前边生成的都会被最后一个覆盖
(function loop(n) {
if (n>=toSendList.length) return; var image = new Image();
image.src = $scope.printObj.notifierObj.url;
image.onload = function () { //为异步函数,所以将创建canvas放在onload中. $("#toPrint3").empty();
$("#toPrint3").append("<canvas id='toPrint_' class='printCanvas'></canvas>");
$scope.printObj.paramList[0].objName = toSendList[n].studentName;
$scope.printObj.paramList[1].objName = toSendList[n].applySchoolName; $("#toPrint_").css("margin-top", (0-$scope.printObj.notifierObj.height)/2+"px");
var canvas = document.getElementById("toPrint_");
canvas.width = $scope.printObj.notifierObj.width;
canvas.height = $scope.printObj.notifierObj.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, $scope.printObj.notifierObj.width, $scope.printObj.notifierObj.height);
$.each($scope.printObj.paramList, function(index, e) {
//canvas的字体不会有12px的兼容性问题
ctx.font = "bold "+e.fontSize+"px "+e.fontFamily;
//canvas写字以字体的左下角为基准,因而要再加一个字体大小的高度
ctx.fillText(e.objName, e.left, e.top+e.fontSize);
});
img.file('录取通知书_' + toSendList[n].studentName + '.png', canvas.toDataURL().substring(22), {base64: true});
$scope.doneNum++;
//刷新成功和失败数量
if(($scope.doneNum + $scope.failedNum) < $scope.progressTotal) {
//更新进度
//$scope.curProgress = Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%";
element.progress('notifierProgress3', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")
} else {
//完成
$scope.curProgress = "100%";
var finishInterval = setInterval(function() {
if($(".layui-progress")[0]) {
element.progress('notifierProgress3', "100%");
clearInterval(finishInterval);
}
}, 200);
$scope.progressDone3 = true;
//去掉转圈
$(".layui-layer-loading").hide(); zip.generateAsync({type:"blob"}).then(function(content) {
saveAs(content, "证书.zip");
});
} loop(n+1);
}
})(0); });
} $scope.closeProgress = function () {
$scope.progressShow = false;
$scope.progressDone = false;
$scope.progressShow2 = false;
$scope.progressDone2 = false;
$scope.progressShow3 = false;
$scope.progressDone3 = false;
layer.closeAll();
} //模板
$scope.printObj = {
notifierObj:{
"url": "/res/img/notifications.png",
"height": "631",
"width": "942"
},
paramList:[{
"objName":"黄大明",
"left":"133",
"top":"191",
"fontSize": "28",
"fontFamily": "KaiTi"
},{
"objName":"SXXX小学",
"left":"460",
"top":"272",
"fontSize": "28",
"fontFamily": "KaiTi"
},{
"objName":"2018",
"left":"195",
"top":"312",
"fontSize": "28",
"fontFamily": "KaiTi"
},{
"objName":"8",
"left":"325",
"top":"312",
"fontSize": "28",
"fontFamily": "KaiTi"
},{
"objName":"31",
"left":"405",
"top":"312",
"fontSize": "28",
"fontFamily": "KaiTi"
}]
} function suitScreen($scope) {
//A4横向标准
var effectiveHeight = 1240;
var effectiveWidth = 1754;
if($scope.printObj.notifierObj.width/effectiveWidth > $scope.printObj.notifierObj.height/effectiveHeight) {
//取最接近的一个属性进行自适应,并适当调小一些
var suitTimes = $scope.printObj.notifierObj.width/effectiveWidth*1.2;
} else {
var suitTimes = $scope.printObj.notifierObj.height/effectiveHeight*1.2;
}
$scope.printObj.notifierObj.width = $scope.printObj.notifierObj.width/suitTimes;
$scope.printObj.notifierObj.height = $scope.printObj.notifierObj.height/suitTimes;
for(i=0;i<$scope.printObj.paramList.length;i++) {
$scope.printObj.paramList[i].fontSize = $scope.printObj.paramList[i].fontSize/suitTimes;
$scope.printObj.paramList[i].left = $scope.printObj.paramList[i].left/suitTimes;
$scope.printObj.paramList[i].top = $scope.printObj.paramList[i].top/suitTimes;
}
} function _fixType(type) {
//imgData是一串string,base64
type = type.toLowerCase().replace(/jpg/i, 'jpeg');
var r = type.match(/png|jpeg|bmp|gif/)[0];
return 'image/' + r;
} function saveFile(data, filename) {
var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
save_link.href = data;
save_link.download = filename; //下载
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
save_link.dispatchEvent(event);
} //方案3使用canvas先画好,然后批量打包保存
function drawNotifier($scope, id, img) {
//canvas需要先定位好,否则画好再动就清除了
//$("#toPrint").css("margin-left", (0-$scope.printObj.notifierObj.width)/2+"px");不可见元素,同样不考虑其左右缩进
$(id).css("margin-top", (0-$scope.printObj.notifierObj.height)/2+"px");
var canvas = document.getElementById(id.substring(1));
canvas.width = $scope.printObj.notifierObj.width;
canvas.height = $scope.printObj.notifierObj.height;
var ctx = canvas.getContext("2d");
var img=new Image();
img.src = $scope.printObj.notifierObj.url;
var deferred=$.Deferred();
var thisObj = $scope.printObj;
//img.onload=function() {
requestAnimationFrame(function() {
//需要onload方法接收,否则画不出
ctx.drawImage(img, 0, 0, thisObj.notifierObj.width, thisObj.notifierObj.height);
//写文字,且要在画好图片之后写,否则会被图片覆盖
$.each(thisObj.paramList, function(index, e) {
//canvas的字体不会有12px的兼容性问题
ctx.font = "bold "+e.fontSize+"px "+e.fontFamily;
//canvas写字以字体的左下角为基准,因而要再加一个字体大小的高度
ctx.fillText(e.objName, e.left, e.top+e.fontSize);
});
deferred.resolve(canvas.toDataURL().substring(22));
})
//}
return deferred.promise(); }

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

说一下中间遇到的问题:

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事件。我就又尝试着用定时器、用回调,都没有成功,而且这样比较容易出现问题。最终找到了一个解决办法,那就是用递归。代码如下

 //图片加载是异步,所有用递归来做,否则前边生成的都会被最后一个覆盖
(function loop(n) {
if (n>=toSendList.length) return; var image = new Image();
image.src = $scope.printObj.notifierObj.url;
image.onload = function () { //为异步函数,所以将创建canvas放在onload中. $("#toPrint3").empty();
$("#toPrint3").append("<canvas id='toPrint_' class='printCanvas'></canvas>");
$scope.printObj.paramList[0].objName = toSendList[n].studentName;
$scope.printObj.paramList[1].objName = toSendList[n].applySchoolName; $("#toPrint_").css("margin-top", (0-$scope.printObj.notifierObj.height)/2+"px");
var canvas = document.getElementById("toPrint_");
canvas.width = $scope.printObj.notifierObj.width;
canvas.height = $scope.printObj.notifierObj.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, $scope.printObj.notifierObj.width, $scope.printObj.notifierObj.height);
$.each($scope.printObj.paramList, function(index, e) {
//canvas的字体不会有12px的兼容性问题
ctx.font = "bold "+e.fontSize+"px "+e.fontFamily;
//canvas写字以字体的左下角为基准,因而要再加一个字体大小的高度
ctx.fillText(e.objName, e.left, e.top+e.fontSize);
});
img.file('录取通知书_' + toSendList[n].studentName + '.png', canvas.toDataURL().substring(22), {base64: true});
$scope.doneNum++;
//刷新成功和失败数量
if(($scope.doneNum + $scope.failedNum) < $scope.progressTotal) {
//更新进度
//$scope.curProgress = Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%";
element.progress('notifierProgress3', Math.round(($scope.doneNum + $scope.failedNum) / $scope.progressTotal * 100) + "%")
} else {
//完成
$scope.curProgress = "100%";
var finishInterval = setInterval(function() {
if($(".layui-progress")[0]) {
element.progress('notifierProgress3', "100%");
clearInterval(finishInterval);
}
}, 200);
$scope.progressDone3 = true;
//去掉转圈
$(".layui-layer-loading").hide(); zip.generateAsync({type:"blob"}).then(function(content) {
saveAs(content, "证书.zip");
});
} loop(n+1);
}
})(0);

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

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

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

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

5.canvas转base64与文件操作:

 //canvas转图片

 canvas.toDataURL().substring(22)

 //js新建文件和文件填充

 var zip = new JSZip();
//zip.file("readme.txt", "证书\n");
var img = zip.folder("images"); img.file('录取通知书_' + toSendList[n].studentName + '.png', canvas.toDataURL().substring(22), {base64: true}); //js文件打包下载 zip.generateAsync({type:"blob"}).then(function(content) {
saveAs(content, "证书.zip");
});

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

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

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

解决方法:使用定时器

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

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

js证书批量生成与打包下载的更多相关文章

  1. java动态生成excel打包下载

    @SuppressWarnings("unchecked") public String batchExport() throws DBException{ @SuppressWa ...

  2. php打包下载以及断点续传

    php下载单文件 以及 多文件打包下载,支持断点续传 断点续传的功能未经验证 需要nginx或者apache服务器指定静态文件,png, mp4, zip等后缀文件的目录, 直接实例化并调用 down ...

  3. linux(以ubuntu为例)下Android利用ant自动编译、修改配置文件、批量多渠道,打包生成apk文件

    原创,转载请注明:http://www.cnblogs.com/ycxyyzw/p/4555328.html  之前写过一篇<windows下Android利用ant自动编译.修改配置文件.批量 ...

  4. 分享一款一直在维护的【网络开发运维|通用调试工具】: http请求, websocket,cmd, RSA,DES, 参数签名工具,脚本批量生成工具,google动态口令,端口检测,组件注册,js混淆...

    首先发下下载地址:https://files.cnblogs.com/files/taohuadaozhu/ConfigLab.Test.ex.rar 日常开发,运维,跨部门跨公司对接中.  想快速调 ...

  5. 使用node.js生成excel报表下载(excel-export express篇)

    引言:日常工作中已经有许多应用功能块使用了nodejs作为web服务器,而生成报表下载也是我们在传统应用. java中提供了2套类库实现(jxl 和POI),.NET 作为微软的亲儿子更加不用说,各种 ...

  6. ASP.NET多文件批量打包下载

    在对多文件打包中用到了 DotNetZip 的方法来实现对多文件压缩打包.需要到http://dotnetzip.codeplex.com/处下载该文件,然后引用即可. Default.aspx: & ...

  7. 使用html2canvas实现批量生成条形码

    /*前台代码*/ <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Generat ...

  8. 2014年最新720多套Android源码2.0GB免费一次性打包下载

    之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年3月份开始不断整理源码区和其他网站上的android源码,目前总共有720套左右,根据实现的功能被我分成了100多个类,总共 ...

  9. JavaWeb多文件上传及zip打包下载

    项目中经常会使用到文件上传及下载的功能.本篇文章总结场景在JavaWeb环境下,多文件上传及批量打包下载功能,包括前台及后台部分.  首先明确一点:  无法通过页面的无刷新ajax请求,直接发下载.上 ...

随机推荐

  1. mongodb遇到的问题

    安装好mongodb之后,服务里默认增加了一个mongodb service的服务,但是服务打不开,右键选择其属性,看他的执行路径执行的是cfg配置文件,看了配置文件里的东西,发现和自己想要的差不多, ...

  2. Git Extensions 和 Tortoisegit 到底是什么?Git For VS(Git For Visual Studio)(Visual Studio 中使用 Git)

    前言: 我们使用 Git 作为版本控制的朋友们,一定都熟悉 Git Extensions 和 Tortoisegit 两款工具,但是对于初学者,可能就不那么了解了. 当然如果有幸,你接触过 SVN , ...

  3. ASP.NET MVC3 在_ViewStart设置Layout使用RenderAction的注意事項

    来源:https://dotblogs.com.tw/lastsecret/archive/2012/03/26/71052.aspx ASP.NET MVC3 在_ViewStart設定Layout ...

  4. [android] sharedPreference入门

    /********************2016年5月6日 更新**************************************/ 知乎:Android 如何实现判断用户首次使用,比如首 ...

  5. Netty实战五之ByteBuf

    网络数据的基本单位总是字节,Java NIO 提供了ByteBuffer作为它的字节容器,但是其过于复杂且繁琐. Netty的ByteBuffer替代品是ByteBuf,一个强大的实现,即解决了JDK ...

  6. ES6之Object.assign()详解

    译者按: 这篇博客将介绍ES6新增的Object.assign()方法. 原文: ECMAScript 6: merging objects via Object.assign() 译者: Funde ...

  7. DevExpress ChartControl ViewType.Line

    源码地址:https://files.cnblogs.com/files/lanyubaicl/ChartControl.Line.7z public partial class Form1 : Fo ...

  8. TCP 三次握手与四次断开

    三次握手建立连接 TCP连接是通过三次握手来连接的. 第一次握手 当客户端向服务器发起连接请求时,客户端会发送同步序列标号SYN到服务器,在这里我们设SYN为x,等待服务器确认,这时客户端的状态为SY ...

  9. 洛谷P2866 [USACO06NOV]糟糕的一天Bad Hair Day(单调栈)

    题目描述 Some of Farmer John's N cows (1 ≤ N ≤ 80,000) are having a bad hair day! Since each cow is self ...

  10. 苹果手机怎么屏幕录屏 ios10怎么录屏

    手机录屏已经现阶段经常使用的功能,有些人喜欢在手机上看视频,看直播.但是有时候看到很精彩的视频,就想要录制下来,这个时候可以采取录屏的方式.那么就涉及到手机怎么录制屏幕视频了?想用苹果手机把手机屏幕录 ...