最近突然被加了要打印证书的功能的需求。其实打印功能很简单,直接调用window.print()就可以打印,只是这是最基本的打印,会打印当前页面的所有元素,而我们要的是局部打印,实现方法:

1.设置好开头与结尾,然后进行识别和打印(前边有介绍),见:https://www.cnblogs.com/ljwsyt/p/9511546.html;

2.使用jqPrint进行打印。jqPrint是对window的打印进行了一些简单便捷的封装,其源代码很少。

地址:https://github.com/MRlijiawei/enroll/blob/master/enroll-webapp/src/main/resources/static/plugins/print/jquery.jqprint-0.3.js

项目要求写一个公共插件,在任何系统都可以使用。但是局限性太大,而且和应用场景有很大关联。如果是做一个拖拽组件,那就只能管理员的角色进行一一拖拽,比较费时;最终暂时写了一个用户自助打印的组件。

思路是使用绝对布局把文字定位到证书图片上相应的位置,然后打印。

html代码:

<div>
<div id="printArea">
<!--startprint942,631-->
<div id="toPrint">
</div>
<!--endprint-->
</div>
<div style="display:none">
<button onclick="printNotifier()">打印</button>
</div>
</div>

有效区域只有一个空的div

css代码:

#toPrint {
position:absolute;
/* background:url('/res/img/notifications.png'); */
left: 50%;
top: 50%;
} #toPrint div {
position:absolute;
} #toPrint img {
position:absolute;
}

可以看到只是设置了一个居中和绝对布局。其余样式在js中动态控制,因为做了自适应和公共化。

js代码:

 myApp.controller('notifierController', function ($rootScope, $scope, services, $sce, $stateParams, $state) {
$scope.services = services; //查询录取通知书内容
services["getApplyStatus"] = function (param) {
return $rootScope.serverAction('/apply/queryDegreeApplyInfo', param, "GET");
}; //模板
$scope.printObj = {
notifierObj:{
"url": "/res/img/notifications.png",
"height": "631",
"width": "942"
},
paramList:[{
"objName":"黄大明",
"left":"133",
"top":"189",
"size": "28"
},{
"objName":"SXXX小学",
"left":"460",
"top":"270",
"size": "28"
},{
"objName":"2018",
"left":"195",
"top":"314",
"size": "28"
},{
"objName":"8",
"left":"325",
"top":"314",
"size": "28"
},{
"objName":"31",
"left":"405",
"top":"314",
"size": "28"
}]
} services.getApplyStatus('token').success(function(res) {
if ('OK' == res.result) {
if(res.msg) {
$scope.printObj.paramList[0].objName = res.msg.studentName;
$scope.printObj.paramList[1].objName = res.msg.applySchoolName; //屏幕自适应
suitScreen($scope);
//组装页面
assembleHtml($scope);
//打印
printNotifier();
}
} else {
layer.alert(res.msg);
}
}); //拖动
/*$(document).on("mousedown","#toPrint",function(e){
//webkit内核和火狐禁止文字被选中
$('body').addClass('select')
//ie浏览器禁止文字选中
document.body.onselectstart=document.body.ondrag=function(){
return false;
}
$scope.moveBegin = true;
$scope.mouseStartPoint = {"left":e.pageX,"top": e.pageY};
});
$(document).on("mouseup",function(e){
$scope.moveBegin = false;
});
$(document).on("mousemove",function(e){
if(!$scope.moveBegin) {
return;
}
$("#toPrint").css("margin-left", e.pageX - $scope.mouseStartPoint.left - 454 + "px");
$("#toPrint").css("margin-top", e.pageY - $scope.mouseStartPoint.top - 315 + "px");
});*/
}); function printNotifier() {
try{
print.portrait = false;//横向打印
}catch(e){
//alert("不支持此方法");
}
var HKEY_RootPath="HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\PageSetup\\";
/*try{
var WSc=new ActiveXObject("WScript.Shell");
HKEY_Key="header";
WSc.RegWrite(HKEY_RootPath+HKEY_Key,"");
HKEY_Key="footer";
WSc.RegWrite(HKEY_RootPath+HKEY_Key,"");
}catch(e){ }*/
$("#printArea").jqprint();
} function suitScreen($scope) {
var effectiveHeight = findParam("#toPrint", "height");
var effectiveWidth = findParam("#toPrint","width");
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].size = $scope.printObj.paramList[i].size/suitTimes;
$scope.printObj.paramList[i].left = $scope.printObj.paramList[i].left/suitTimes;
$scope.printObj.paramList[i].top = $scope.printObj.paramList[i].top/suitTimes;
}
} function assembleHtml($scope) {
var htmlStr = "<img src='" + $scope.printObj.notifierObj.url+"' style='width:"+$scope.printObj.notifierObj.width+"px;height:"+
$scope.printObj.notifierObj.height+"px'>";
for(i=0;i<$scope.printObj.paramList.length;i++) {
var nowObj = $scope.printObj.paramList[i];
htmlStr += "<div style='font-size:"+nowObj.size+"px;top:"+nowObj.top+"px;left:"+nowObj.left+"px'>"+nowObj.objName+"</div>";
}
$("#toPrint").css("margin-left", (0-$scope.printObj.notifierObj.width)/2+"px");
$("#toPrint").css("margin-top", (0-$scope.printObj.notifierObj.height)/2+"px");
$("#toPrint").css("height", $scope.printObj.notifierObj.height+"px");
$("#toPrint").css("width", $scope.printObj.notifierObj.width+"px");
$("#toPrint").append(htmlStr);
} //获取有效区域
function findParam(targetObj, attribute) {
//取数字
if($(targetObj).css(attribute) && $(targetObj).css(attribute).replace(/[^0-9]/ig,"") != '0') {
return $(targetObj).css(attribute).replace(/[^0-9]/ig,"");
} else {
//递归
return findParam($(targetObj).parent(), attribute);
}
}

angular1的框架。

其中有几个关键思路:

(1)模板结构定义,及根据参数长度动态生成页面。

(2)屏幕自适应,选取比较接近的(宽或高),然后计算倍数,并做了1.2倍的缩小,使其不至于都挨着页面边界不美观。取有效宽度时,从需要打印的元素往上层parent一层层递归取,直到取到有效的宽和高。递归时,由于已开始没有return,导致一直取不到最终值

return findParam($(targetObj).parent(), attribute);

(3)拖动实现,已注掉的那段mouse事件,思路是点击目标元素时开始计算坐标,放开时停止,中间移动的动作根据坐标偏移量来调整目标的left和top。有个小瑕疵就是有时候放开之后再点击就回到页面中间去了,由于后来做了页面大小的自适应就没有管了。

(4)打印的时候一些设置。由于是自动打印,不能要求用户手动我改设置,主要是两个,一个是基本上证书都是横向,所有打印要改成默认横向,然后去掉页眉页脚,实现的代码是

try{
print.portrait = false;//横向打印
}catch(e){
//alert("不支持此方法");
}

下边注释掉的网上说的是去掉页眉页脚用的,但是实测加上之后反而去不掉了。

开发完成之后,基本功能也都OK了,然后就是考虑兼容性的问题了。自适应解决了很大程度上的兼容性问题,但是对于浏览器的兼容性和移动端的兼容性还需要再进行测试。

经测试,在移动端的时候,如果屏幕分辨率较小,那么就会出现子题比较小的情况。而谷歌对于小于12px的字体,大小始终固定在12不会再变小,这就出现了兼容性问题。

解决思路是按比例缩放,使用属性是-webkit-transform。而缩放默认是以中心为原点进行缩放,而我们画图填充是以左上角为原点的,所有缩放的同时还必须使用transform-origin:0 0设置以左上角为基准进行缩放。

最后就是,如果大于12px而又进行了缩放,那么就会变得更大,所有我们给这两个样式设置一个条件,那就是以12px作为临界点。

代码如下:

 function assembleHtml($scope) {
var htmlStr = "<img src='" + $scope.printObj.notifierObj.url+"' style='width:"+$scope.printObj.notifierObj.width+"px;height:"+
$scope.printObj.notifierObj.height+"px'>";
for(i=0;i<$scope.printObj.paramList.length;i++) {
var nowObj = $scope.printObj.paramList[i];
if(nowObj.size < 12) {
htmlStr += "<div style='font-size:"+nowObj.size+"px;top:"+nowObj.top+"px;left:"+nowObj.left+
//谷歌浏览器字体小于12px时会不再变小,使用-webkit-transform兼容,并设置已左上角作为变换原点
"px;-webkit-transform:scale("+nowObj.size/12+","+nowObj.size/12+");transform-origin:0 0'>"+nowObj.objName+"</div>";
} else {
htmlStr += "<div style='font-size:"+nowObj.size+"px;top:"+nowObj.top+"px;left:"+nowObj.left+
"px'>"+nowObj.objName+"</div>";
}
}
$("#toPrint").css("margin-left", (0-$scope.printObj.notifierObj.width)/2+"px");
$("#toPrint").css("margin-top", (0-$scope.printObj.notifierObj.height)/2+"px");
$("#toPrint").css("height", $scope.printObj.notifierObj.height+"px");
$("#toPrint").css("width", $scope.printObj.notifierObj.width+"px");
$("#toPrint").append(htmlStr);
}

附上效果对比图,更容易理解些

其中“类好啊”是未变换未设置原点的最终效果,“北门小学”是都设置后的效果,下边的日期是设置了缩放但是没有设置原点的效果。

还有一个很关键的步骤就是定义好模板之后获取数据并替换掉模板中的值。原本设计要做一个通用的,但是就要存库,而且一个模板一张图片就要存一次,而且对于值的获取后台也不好处理,所有暂时就直接js中定义模板了。

整个流程很简洁也很实用,希望大家喜欢。感谢大家支持,求关注,求红包奖励金。

js开发打印证书功能的更多相关文章

  1. js开发打印证书功能(二)

    在上一篇的基础上,实现了一下另外一种方式. 上一篇地址:https://www.cnblogs.com/ljwsyt/p/9525290.html 首先,该方式也是有几种方法. 1.在上一篇的基础上, ...

  2. 网站开发进阶(十二)JS实现打印功能(包括打印预览、打印设置等)

    JS实现打印功能(包括打印预览.打印设置等) 绪 最近在进行项目开发时,需要实现后台管理端打印功能,遂在网上一阵搜索,搜到了很多相关的文章.其中绝大部分文章都是使用的Lodop5.0(Web打印和套打 ...

  3. 浅试WebStorm配置Node.js开发环境

    web前端开发IDE一直喜欢用WebStorm,这里简单介绍如何用WebStorm搭建一个Node.js开发环境. 首先,需要在本地安装好node.js,以及npm包管理工具.你也可以吧node.js ...

  4. Koa与Node.js开发实战(2)——使用Koa中间件获取响应时间(视频演示)

    学习架构: 在实战项目中,经常需要记录下服务器的响应时间,也就是从服务器接收到HTTP请求,到最终返回给客户端之间所耗时长.在Koa应用中,利用中间件机制可以很方便的实现这一功能.代码如下所示: 01 ...

  5. Node.js学习笔记——Node.js开发Web后台服务

    一.简介 Node.js 是一个基于Google Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...

  6. .NET开发邮件发送功能的全面教程(含邮件组件源码)

    今天,给大家分享的是如何在.NET平台中开发“邮件发送”功能.在网上搜的到的各种资料一般都介绍的比较简单,那今天我想比较细的整理介绍下: 1)         邮件基础理论知识 2)         ...

  7. MVC5 网站开发之七 用户功能 3用户资料的修改和删除

    这次主要实现管理后台界面用户资料的修改和删除,修改用户资料和角色是经常用到的功能,但删除用户的情况比较少,为了功能的完整性还是坐上了.主要用到两个action "Modify"和& ...

  8. MVC5 网站开发之八 栏目功能 添加、修改和删除

    本次实现栏目的浏览.添加.修改和删除. 栏目一共有三种类型. 常规栏目-可以添加子栏目,也可以添加内容模型.当不选择内容模型时,不能添加内容. 单页栏目-栏目只有一个页面,可以设置视图. 链接栏目-栏 ...

  9. 移动端报表JS开发示例--获取定位

    上次分享了移动端报表JS开发的系统概念,后来我又回去摸索了一些案例.之前接触到的FineReport的APP客户端可以用来打卡签到,就好奇研究了以下,这次就来聊一聊报表移动端开发如何实现定位功能. 1 ...

随机推荐

  1. 【设计模式】不同设计模式体现IOC控制反转

    使用过Spring的开发者应该都对IOC控制反转功能有所了解,最开始学习时应该都知道使用依赖注入来实现IOC的功能,本文来介绍使用IOC控制反转思想的几种设计模式. 依赖注入来实现IOC 注入依赖是I ...

  2. 【Java每日一题】20170302

    20170301问题解析请点击今日问题下方的“[Java每日一题]20170302”查看(问题解析在公众号首发,公众号ID:weknow619) package Mar2017; public cla ...

  3. margin:0 auto是什么意思

    一.margin设置对象外边距 二.margin后面如果只有两个参数的话,第一个表示top和bottom,第二个表示left和right 因为0 auto

  4. jQuery效果之简单的手风琴效果

    实现效果如图所示: html结构: <div class="item_box box10"> <div class="item_box_wp" ...

  5. HTML5中的input type为file控件限制上传文件类型及扩展

    简单介绍 input file控件限制上传文件类型如下:1.文件类型中间用,分开:2.html和htm这样的要写成两个: 3实例: <input type="file" na ...

  6. 洛谷P4104 [HEOI2014]平衡(dp 组合数学)

    题意 题目链接 Sol 可以把题目转化为从\([1, 2n + 1]\)中选\(k\)个数,使其和为\((n+1)k\). 再转化一下:把\((n+1)k\)划分为\(k\)个数,满足每个数在范围在\ ...

  7. SqlMapConfig配置加注解

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC & ...

  8. iOS----------The app's Info.plist must contain an NSPhotoLibraryUsageDescription key

    This app has crashed because it attempted to access privacy-sensitive data without a usage descripti ...

  9. 生成器(generator,yield),next,send

    #生成器 def generator(): for i in range(200): yield '哇哈哈%s' %i g = generator() #调用生成数函数,接受作用 ret = g.__ ...

  10. 深圳市共创力咨询为某大型上市企业提供两天的UCD内训与辅导服务!

    2017年5月23和24日两天,深圳市共创力咨询为国内某大型上市企业提供了为期两天的内训与辅导服务.本次执行培训与辅导任务的是UCD(基于用户体验的设计)资深顾问蔷薇女士.蔷薇老师分别从UCD理论.U ...