jquery.print web打印jquery插件

jquery.print web打印jquery插件

月光魔力鸭

2018-09-21 13:54 阅读 1008 喜欢 0 jquery插件print web打印插件

关于web打印,需要对页面内容进行页面样式设置,呈现出分页的样子,同时对于题目中的图片或表格尽量不分到两个页面中,因此实现了一个jquery的web打印插件,当然,这个插件目前只适用于部分情况,仅供借鉴!

具体实现的功能

代码

/***
 *
 * 针对页面打印进行调整样式和DOM
 * @since 2018年9月18日 09:00:31
 ****/
 (function($){

 	var methods = {
 		//初始化
 		init : function( options ){
 			var settings = $.extend({},this.print.defaults,options);
 			//根据目前部分属性,设置对应的其他属性
 			var sizeObj = settings['sizes'][settings.size];
 			settings['bodyWidth'] = sizeObj.width;
 			settings['pageWidth'] = (sizeObj.width - 4 - settings['paddingLeft'] * 2 - settings['contentMargin']*settings['columns']) / settings['columns'];
 			settings['pageHeight'] = sizeObj.height;
 			$(this).print('setSettings',settings);
 			//预处理//创建分页
 			$(this).print('preInt').print('createPage');
 			return $(this);
 		},
 		//预处理:将页面呈现出对应的样式,去除一些需要过滤的点来
 		preInt : function(){
 			var $this = $(this),settings = $this.print('getSettings'),
 				pageWidth = settings['pageWidth'],
 				childClass = settings['childClass'],
 				paddingHeight = settings['paddingTop'] * 2,
 				pageHeight = settings['pageHeight'],
 				breakHeight = settings['breakHeight'];
 			//设置当前容器宽度,让内容根据宽度呈现出对应的高度来
 			$this.attr('style','width:'+pageWidth+'px;margin:0px auto;')
 			//去除自带的分页样式
 			$this.find('[style*="page-break-before"]').each(function(){
				$(this).attr('style',$(this).attr('style').replace('page-break-before:always',''))
			});
			//将容器下第一级优先处理大于一页的内容
			$this.children('.'+childClass).each(function(){
				var $child = $(this),height = $child.outerHeight(true);//获得高度
				if(height+paddingHeight > pageHeight){
					var childs = $child.children();
					if(childs.length > 1){//有多个子结构,则每个结构全都分开
						childs.each(function(){
							var $temp = $('<div></div>').addClass(childClass);
							 $temp.append($(this));
							 $child.before($temp);
						})
						$child.remove();
					}else{
						//如果只有一个标签,则继续查看是否有下级标签
						var $c = $(childs[0]);//获得第一个标签
						var cc = $c.children();
						var dt  = $c.offset().top;
						if(cc.length > 1){//子标签下含有多个子标签
							//每隔300像素一个标签进行换行
							var temp = [],count = 1;
							cc.each(function(){
								var $cc = $(this);
								var st = $cc.offset().top;
								if( (st - dt)< (count*breakHeight) ){
									temp.push($cc);
								}else{
									count++;
									var $temp = $('<div></div>').addClass(childClass);
									var $cloneP = $c.clone();
									$cloneP.empty();
									temp.forEach(function(item){
										$cloneP.append(item.clone());
									})
									$temp.append($cloneP);
									$child.before($temp);
									temp = [$cc];
								}
							})
							if(temp.length > 0){
								var $temp = $('<div></div>').addClass(childClass);
								var $cloneP = $c.clone().empty();
								temp.forEach(function(item){
									$cloneP.append(item);
								})
								$temp.append($cloneP);
								$child.before($temp);
								temp = [];
							}
							$child.remove();//删除
						}else{//一个标签都没有,全是字或者就一个标签
							//多级还是一个标签的,暂时不考虑,目前没有处理办法。
							throw new Error('存在内容超过一页且无法处理的内容,建议在录入的时候简单处理。')
						}
					}
				}
			})
			return $this;
 		},
 		//根据子级内容DOM创建分页容器
 		createPage : function(){
 			var $this = $(this),settings = $this.print('getSettings'),
 				paddingHeight = settings['paddingTop'] * 3,
 				pageHeight = settings['pageHeight'],
 				pageWidth = settings['pageWidth'],
 				useDot = settings['useDot'],
 				dotId = settings['dotId'],
 				dotHeight = settings['dotHeight'],
 				dotWidth = settings['dotWidth'],
 				dotClass = settings['dotClass'],
 				pageClass = settings['pageClass'],
 				contentClass = settings['contentClass'],
 				columns = settings['columns'],
 				bodyWidth = settings['bodyWidth'];
 			var childs = $this.children();
			//从上向下计算,达到符合条件后,就把符合条件的放到一个dom中
			var pageArr = [],//最终的结果
				temp = [],//临时页面
				tempHeight = 0,
				pyHeight = 0,//偏移距离
				nowPageIndex = 1;//当前的页面索引
			childs.each(function( index,item ){
				var $item = $(item);
				//如果是js,则调过
				if(item.tagName == 'SCRIPT'){
					return true;
				}
				var allHeight = $item.outerHeight(true);//真实的整体高度
				var top = $item.offset().top;//距离顶部距离
				var height = $item.height();//除去margin padding的高度(肉眼高度)
				//实际top
				var rtop = top + pyHeight;
				if(rtop +  height + paddingHeight > (pageHeight * nowPageIndex) ){
					//开始下一页,并计算偏移距离,重置参数
					// console.log(nowPageIndex);
					pyHeight = ( pageHeight * nowPageIndex + parseInt(($item.css('margin-top') || '0px').replace('px'),10) - top) + 0;
					pageArr.push(temp);
					temp = [$item];
					nowPageIndex++;
				}else{
					temp.push($item);
				}
			})
			pageArr.push(temp);
			//重置DOM
			$this.empty();
			//重新处理DOM
			for(var i=0;i<pageArr.length;i+=columns){
				var $page = $('<div></div>');
				//如果有dot需求,则增加
				if(useDot){
					var $dot1 = $('<span></span>').addClass(dotClass).attr('style','left:0px;top:0px;width:'+dotWidth+'px;height:'+dotHeight+'px;').attr('id',dotId);
					var $dot2 = $('<span></span>').addClass(dotClass).attr('style','right:0px;top:0px;width:'+dotWidth+'px;height:'+dotHeight+'px;');
					var $dot3 = $('<span></span>').addClass(dotClass).attr('style','left:0px;bottom:0px;width:'+dotWidth+'px;height:'+dotHeight+'px;');
					$page.append($dot1);
					$page.append($dot2);
					$page.append($dot3);
				}
				//添加样式和页码
				$page.addClass(pageClass).attr('pageindex',i+1).attr('style','height:'+pageHeight+'px;')
				for(var j=0;j<columns;j++){
					var $content = $("<div></div>").addClass(contentClass).attr('style','width:'+pageWidth+'px;float:left;')
					var item = pageArr[i+j];
					if(item){
						item.forEach(function(item2){
							$content.append(item2);
						})
						$page.append($content);//添加多个列
					}
				}
				$this.append($page);
			}
			//还原容器A4/3宽度
			$this.attr('style','width:'+bodyWidth+'px;margin:0px auto;');//设置body宽度,先进行计算
			return $this;
 		},
 		//获得某些选中针对锚点相对距离
 		getPos : function( checkSelector ){
 			var $this = $(this),settings = $this.print('getSettings'),
 				pageClass = settings['pageClass'],
 				dotId = settings['dotId'];

 			var result = [];
			$this.find(checkSelector).each(function(){
				var $check = $(this);
				var left = $check.offset().left;
				var top = $check.offset().top;
				var $dot = $check.parents('.'+pageClass).find('#'+dotId);
				var dl = $dot.offset().left;
				var dt = $dot.offset().top;
				var rsLeft = left - dl;
				var rsTop = top - dt;
				var rs = {
					left : rsLeft,
					top : rsTop
				}
				result.push(rs);
			})
			return result;
 		},

 		//设置settings
 		setSettings : function(settings){
 			$(this).data('settings',settings);
 		},
 		//获得设置项目
 		getSettings: function(name) {
 			if(name){
 				return $(this).data('settings')[name];
 			}else{
 				return $(this).data('settings');
 			}
        }
 	};
 	$.fn.print = function(method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method with name ' + method + ' does not exists for jQuery.print');
        }
    };
    //默认的属性
    $.fn.print.defaults = {
    	sizes : {
    		'a4' : {
    			width : 1184,
    			height : 1672
    			// width:600,
    			// height : 800
    		},
    		'a3' : {
    			width : 3000,
    			height : 4000
    		}
    	},
    	size : 'a4',//默认A4大小
    	columns : 1,
    	pageClass : 'page',//外层样式--页面
    	contentClass : '',//page下content的样式
    	contentMargin : 0,//内容的外边据,多个需要控制距离呈现高度
    	paddingTop : 30,//页面中顶部空白距离,底部相同
    	paddingLeft : 30,//页面中左侧空白距离,右侧同样
    	useDot : true,//是否启用锚点进行标识页面位置
    	dotClass: 'dot',//dot对应的样式
    	dotWidth : 30,//默认宽度30px
    	dotHeight : 30,//默认高度30px
    	dotId : 'dot',//计算距离的点的ID
    	childClass : 'timu',//子级的样式,用于包裹、判断,每个子级都要有
    	breakHeight : 200//如果出现一行超过一页,那么设置多少像素超过则自动换行
    }

 })(window.jQuery || $);

使用

根据 $.fn.print.defaults 提供的内置参数,可以进行配置。如下:

$('body').print({
     size : 'a4',//a3
     columns : 2,//一页几列
     dotWidth : 30,
     dotHeight : 20,
     paddingTop : 50,
     paddingLeft : 20,
     pageClass : 'comba',
     contentClass : 'content',
     contentMargin : 10
 });

使用后效果

未调用前 使用后

注意事项

在使用的时候,对应的页面样式一定要与设置的宽度相对应,否则呈现的效果可能不太正确。 如果页面中有图片的话,可以稍微延迟下调用时间,让图片都加载出来后处理,最好还是直接指定图片的宽高。

转载请注明出处: https://chrunlee.cn/article/web-print-jquery-plugin.html


感谢支持!

赞赏支持
提交评论
评论信息 (请文明评论)
暂无评论,快来快来写想法...
推荐
突然来了一个调研任务,想要实现一个类似3D虚拟展厅类似的需求,主要就是放一些学生的作品,然后预览啥的,效果还是要全景的效果。 经过一番调查,最终锁定了以前从未接触过的krpano。
之前的时候都是在各大主机厂商手动进行申请免费的,直到阿里的免费期限变更为3个月.. 我就开始觉的有些麻烦了,还不如使用这个let's encrypt进行部署呢。
this 是 JavaScript 的一大难点,多年经验的前端程序员都可能对这方面模糊。this 在大量的函数、类库中都有使用,理清显式绑定和隐式绑定有助于理解或书写这类函数。
在使用echarts 来做统计报表的时候,由于数量较多,准备将同类型的相同属性抽取出来,然后用来做默认属性的。结果发现一个问题
今天刷codewars的题目的时候碰到一个通过js来实现字符串转base64的题目,base64虽然在js或nodejs中经常用,但是我还真没有仔细去看过原理以及如何实现,这回绕不过去了,赶紧找了找资料看了下。
web开发中,前台有时候会需要一个随机数或序列,通常来说,这个随机数可能只在当前页面中使用,并不需要太过严格,大体上重复率低即可。
项目中需要使用treegrid,找了下easyui 和 ext都有,但是项目用的框架是 byyui,如果为了treegrid 就把这些都加载的话,感觉不太合算。找了大家常用的基于jquery的treegrid.
在文件上传的时候,经常会对文件的mime进行限制,比如图片 image/jpg 等,让用户可以选择图片,而不是其他的文件。