开发业务系统经常需要打印打印某个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();
});
},
文章评论