开发业务系统经常需要打印打印某个div(如打印业务系统生成的表单),而不是打印整个页面,这里分享我自用的工具代码,并不依赖框架,在原生Javascript下或者Vue下都能使用。
首先准备printArea.js,如下,保存成printArea.js,后面在html里引入js的时候用到。
/* * Copyright (c) 2021. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = global || self, (global.index = global.index || {}, global.index.js = factory())); }(this, function () { 'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var PrintArea = /*#__PURE__*/ function () { function PrintArea(ele, options) { _classCallCheck(this, PrintArea); this.counter = 0; this.modes = { iframe: "iframe", popup: "popup" }; this.standards = { strict: "strict", loose: "loose", html5: "html5" }; var defaults = { mode: this.modes.iframe, standard: this.standards.html5, popHt: 500, popWd: 400, popX: 200, popY: 200, popTitle: '', popClose: true, extraCss: '', extraHead: '', retainAttr: ["id", "class", "style"] }; this.settings = Object.assign({}, defaults, options); this.idPrefix = "printArea_"; this.ele = ele.nodeType === 1 ? ele : document.querySelector(ele); } _createClass(PrintArea, [{ key: "print", value: function print() { var _this = this; this.counter++; var prefixList = document.querySelectorAll("[id^=" + this.idPrefix + "]"); while (prefixList.length) { prefixList[0].parentNode.removeChild(prefixList[0]); prefixList = document.querySelectorAll("[id^=" + this.idPrefix + "]"); } this.settings.id = this.idPrefix + this.counter; var PrintAreaWindow = this.getPrintWindow(); this.write(PrintAreaWindow.doc, this.ele); setTimeout(function () { _this.windowPrint(PrintAreaWindow); }, 1000); } }, { key: "windowPrint", value: function windowPrint(PAWindow) { var paWindow = PAWindow.win; paWindow.focus(); paWindow.print(); if (this.settings.mode === this.modes.popup && this.settings.popClose) { setTimeout(function () { paWindow.close(); }, 1000); } } }, { key: "write", value: function write(PADocument, element) { PADocument.open(); PADocument.write(this.docType() + "<html>" + this.getHead() + this.getBody(element) + "</html>"); PADocument.close(); } }, { key: "docType", value: function docType() { if (this.settings.mode === this.modes.iframe) { return ""; } if (this.settings.standard === this.standards.html5) { return "<!DOCTYPE html>"; } var transitional = this.settings.standard === this.standards.loose ? " Transitional" : ""; var dtd = this.settings.standard === this.standards.loose ? "loose" : "strict"; return '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01' + transitional + '//EN" "http://www.w3.org/TR/html4/' + dtd + '.dtd">'; } }, { key: "getHead", value: function getHead() { var extraHead = ""; if (this.settings.extraHead) { this.settings.extraHead.replace(/([^,]+)/g, function (m) { extraHead += m; }); } var linkList = document.querySelectorAll('link'); linkList = Array.from(linkList).filter(function (item) { var relAttr = item.getAttribute("rel"); return relAttr && relAttr.toLowerCase() === 'stylesheet'; }).filter(function (item) { var mediaAttr = item.getAttribute("media"); return !mediaAttr || mediaAttr.toLowerCase() === 'print' || mediaAttr.toLowerCase() === 'all'; }).map(function (item) { var href = item.getAttribute("href"); return "<link type=\"text/css\" rel=\"stylesheet\" href=\"".concat(href, "\" >"); }); if (this.settings.extraCss) { this.settings.extraCss.replace(/([^,\s]+)/g, function (m) { extraHead += '<link type="text/css" rel="stylesheet" href="' + m + '">'; }); } return "<head><title>" + this.settings.popTitle + "</title>" + extraHead + linkList.join('\n') + "</head>"; } }, { key: "getBody", value: function getBody(element) { var html = ""; var attrs = this.settings.retainAttr; var ele = this.getFormData(element); var attributes = ""; attrs.forEach(function (attr) { var eleAttr = ele.getAttribute(attr); if (eleAttr) { attributes += (attributes.length > 0 ? " " : "") + attr + "='" + eleAttr + "'"; } }); html += '<div ' + attributes + '>' + ele.innerHTML + '</div>'; return "<body>" + html + "</body>"; } }, { key: "getFormData", value: function getFormData(ele) { var copy = ele.cloneNode(true); var copiedInputs = copy.querySelectorAll("input,select,textarea"); Array.from(ele.querySelectorAll("input,select,textarea")).forEach(function (item, index) { var typeInput = item.getAttribute("type"); if (!typeInput) { var targetName = item.nodeName; typeInput = targetName === 'SELECT' ? "select" : targetName === 'TEXTAREA' ? "textarea" : ""; } var copiedInput = copiedInputs[index]; if (typeInput === "radio" || typeInput === "checkbox") { copiedInput.removeAttribute('checked'); if (item.checked) { copiedInput.setAttribute('checked', true); } } else if (typeInput === "text" || typeInput === "") { copiedInput.setAttribute("value", item.textContent); } else if (typeInput === "select") { var options = item.querySelectorAll('option'); var copiedOptions = copiedInput.querySelectorAll('option'); Array.from(options).forEach(function (option, optionIndex) { copiedOptions[optionIndex].removeAttribute('selected'); if (option.selected) { copiedOptions[optionIndex].setAttribute('selected', true); } }); } else if (typeInput === "textarea") { copiedInput.textContent = item.value; } }); return copy; } }, { key: "getPrintWindow", value: function getPrintWindow() { switch (this.settings.mode) { case this.modes.iframe: var f = this.Iframe(); return { win: f.contentWindow || f, doc: f.doc }; case this.modes.popup: var p = this.Popup(); return { win: p, doc: p.doc }; } } }, { key: "Iframe", value: function Iframe() { var frameId = this.settings.id; var iframeStyle = 'border:0;position:absolute;width:0px;height:0px;right:0px;top:0px;'; var iframe; try { iframe = document.createElement('iframe'); document.body.appendChild(iframe); iframe.setAttribute('style', iframeStyle); iframe.setAttribute('id', frameId); iframe.setAttribute('src', "#" + new Date().getTime()); iframe.doc = null; iframe.doc = iframe.contentDocument ? iframe.contentDocument : iframe.contentWindow ? iframe.contentWindow.document : iframe.document; } catch (e) { throw e + ". iframes may not be supported in this browser."; } if (iframe.doc == null) throw "Cannot find document."; return iframe; } }, { key: "Popup", value: function Popup() { var windowAttr = "location=yes,statusbar=no,directories=no,menubar=no,titlebar=no,toolbar=no,dependent=no"; windowAttr += ",width=" + this.settings.popWd + ",height=" + this.settings.popHt; windowAttr += ",resizable=yes,screenX=" + this.settings.popX + ",screenY=" + this.settings.popY + ",personalbar=no,scrollbars=yes"; var newWin = window.open("", "_blank", windowAttr); newWin.doc = newWin.document; return newWin; } }]); return PrintArea; }(); window.PrintArea = PrintArea; return PrintArea; }));
下面原生Html/JS下实现调用打印:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Untitled Document</title> <!-- 引入printArea.js --> <script type="text/javascript" src="printArea.js"></script> <!-- 可加载css,也可以使用@media print来指定特定在打印的时候才显示的样式 <link rel="stylesheet" type="text/css" href="xxx.css"> --> @media print { /* 这里还可以将不需要打印出来的地方直接用display:none;隐藏。 */ td, tr { page-break-inside: avoid; } /* 用于设置是否在指定元素中插入分页,avoid 避免在元素内部插入分页符。 */ } </head> <body> <button onclick="print2()">打印</button> <!-- 这里是需要局部打印的内容,不显示在网页上,只需要打印,所以display: none; --> <div style="display: none;"> <div id="print2" style="width: 900px; margin:0 auto;color:black;font-family: SimHei,黑体,SimSun,serif;"> <h4 style="text-align:center;">测试打印内容</div> </div> </div> <script type="text/javascript"> function print2() { const printArea = new PrintArea(document.getElementById('print2'),{}); printArea.print(); } </script> </body> </html>
怎么样,是不是很简单,总结下来,就是需要打印的时候,调用:
// new PrintArea第一个参数接收一个需要打印的区域,我们这里用id为print2来选取:document.getElementById('print2') const printArea = new PrintArea(document.getElementById('print2'),{}); printArea.print();
需要打印的上层,用一个隐藏的div包起来,这样就不会显示在主页面上了。
如果需要在vue里调用呢?也很简单(这里使用到了$nextTick),html里面正常引入printArea.js,需要打印的区域也用div包起来,很上面纯html实现一样,最后调用打印的代码如下:
// vue下使用printArea.js打印 printClicked2: function() { var _this = this; _this.$nextTick(function () { const printArea = new PrintArea(document.getElementById('print2'),{}); printArea.print(); }); },
文章评论