cause
Vue
project, there is a need to print (export pdf
), so I searched for several plug-ins on the Internet, including vue plug-in and
js plug-in, either too heavy and not lightweight enough, or the function is not perfect enough, in the end none of the plug-ins met the requirements.
After searching for plug-ins and data, I found that the printing principle is not difficult, so I tried to write a plug-in by myself, the effect is very good, and very lightweight.
Effect picture
The following is a partial print screenshot of the actual project:
use
During use, you only need to pass in the dom
element to vue
is used in ref
. It should be noted that the css
to be printed does not depend on other elements and must be displayed independently, for example, in the following example resume-container
element cannot rely on box
, otherwise it will cause part of the style to be lost when printing.
Examples are as follows:
<template>
<div class="box">
<div class="resume-container" ref="resume">
</div>
</div>
</template>
<script>
// 引入打印插件
import printHtml from "@/utils/print.js"
export default {
methods: {
// 创建打印方法
print() {
// 传入要打印的dom
printHtml(this.$refs.resume, () => {
location.reload();
})
},
},
}
</script>
<style scoped rel="stylesheet/scss" lang="scss">
/* 设置打印格式 */
@page {
margin: 0; /* this affects the margin in the printer settings */
size: A4;
}
/* 设置打印样式 */
@media print {
.resume-container {
font-size: 1.473vh !important;
}
}
.box {
width: 100vw;
}
/* 要打印的dom元素为最外层元素,样式不依赖于其他元素 */
.resume-container {
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 1.35vh;
font-weight: 300;
letter-spacing: 0.1vw;
-webkit-print-color-adjust:exact;
-moz-print-color-adjust:exact;
-ms-print-color-adjust:exact;
}
</style>
Source code
const VueHtmlToPaper = function(dom, cb) {
if (!(this instanceof VueHtmlToPaper)) return new VueHtmlToPaper(dom, cb);
if (!cb) cb = function() { return true; };
if ((typeof dom) === "string") {
this.dom = document.querySelector(dom);
} else {
this.isDOM(dom)
this.dom = this.isDOM(dom) ? dom : dom.$el;
}
const styles = this.getStyle();
const content = this.getHtml();
console.log(styles, content)
const defaultName = '_blank',
defaultSpecs = ['fullscreen=yes','titlebar=yes', 'scrollbars=yes'],
defaultReplace = true;
const url = '';
const win = window.open(url, defaultName, defaultSpecs, defaultReplace);
win.document.write(`
<html>
<head>
<title>${document.title}</title>
${styles}
</head>
<body>
${content}
</body>
</html>
`);
setTimeout(() => {
win.document.close();
win.focus();
win.print();
win.close();
cb();
}, 1000);
return true;
}
VueHtmlToPaper.prototype = {
calenderFlag: false,
getStyle: function () {
var str = "",
styles = document.querySelectorAll('style, link');
if (document.getElementById('calender-task-flag')) {
this.calenderFlag = true;
}
if (this.calenderFlag) {
const c_height = window.innerHeight;
const c_width = window.innerWidth;
const boxes = document.getElementsByClassName('resize-box');
for (let i = 0; i < boxes.length; i++) {
const box = boxes[i];
const width = this.getAttr(box, 'width');
const height = this.getAttr(box, 'height');
const top = this.getAttr(box, 'top');
const left = this.getAttr(box, 'left');
//const widthScale = 1;
const widthScale = 0.8;
//parent.style.width = this.pxStrToNumber(width) / widthScale / c_width * 100 + '%';
box.style.width = this.pxStrToNumber(width) / widthScale / c_width * 100 + '%';
//parent.style.height = this.pxStrToNumber(height) / c_height * 100 + '%';
box.style.height = this.pxStrToNumber(height) / c_height * 100 + 'vh';
box.style.left = this.pxStrToNumber(left) / widthScale / c_width * 100+ '%';
box.style.top = this.pxStrToNumber(top) / c_height * 100 + 'vh';
box.style.border = '0.5px solid #909399';
box.style.color = 'white';
this.prefixStyle('transform');
document.getElementById('printMe');
//container.style[transform] = 'scale(0.5) translate(-50%, -50%)';
// container.style.height = '100vh';
// container.style.overflow = 'hidden';
}
}
for (var i = 0; i < styles.length; i++) {
str += styles[i].outerHTML;
}
str += "<style>" + '.no-print' + "{display:none;}</style>";
str += "<style> body { margin: 0; padding: 0 } </style>";
return str;
},
getHtml: function () {
var inputs = document.querySelectorAll('input');
var textareas = document.querySelectorAll('textarea');
var selects = document.querySelectorAll('select');
for (var k = 0; k < inputs.length; k++) {
if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
if (inputs[k].checked == true) {
inputs[k].setAttribute('checked', "checked")
} else {
inputs[k].removeAttribute('checked')
}
} else if (inputs[k].type == "text") {
inputs[k].setAttribute('value', inputs[k].value)
} else {
inputs[k].setAttribute('value', inputs[k].value)
}
}
for (var k2 = 0; k2 < textareas.length; k2++) {
if (textareas[k2].type == 'textarea') {
textareas[k2].innerHTML = textareas[k2].value
}
}
for (var k3 = 0; k3 < selects.length; k3++) {
if (selects[k3].type == 'select-one') {
var child = selects[k3].children;
for (var i in child) {
if (child[i].tagName == 'OPTION') {
if (child[i].selected == true) {
child[i].setAttribute('selected', "selected")
} else {
child[i].removeAttribute('selected')
}
}
}
}
}
return this.dom.outerHTML;
},
isDOM: (typeof HTMLElement === 'object') ?
function (obj) {
return obj instanceof HTMLElement;
} :
function (obj) {
return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
},
getAttr: function(element, attr) {
return window.getComputedStyle ? window.getComputedStyle(element, )[attr] : element.currentStyle[attr];
},
pxStrToNumber: function(pxStr) {
return Number(pxStr.slice(0, pxStr.length - 2));
},
vender: (function() {
let elementStyle = document.createElement('div').style;
let transformNames = {
webkit: 'webkitTransform',
Moz: 'MozTransform',
O: 'OTransform',
ms: 'msTransform',
standard: 'transform',
};
for(let key of Object.keys(transformNames)) {
if (elementStyle[transformNames[key]] !== undefined) return key;
}
return false;
})(),
prefixStyle: function(style) {
if (this.vender === false) return false;
if (this.vender === 'standard') return style;
return this.vender + style.charAt(0).toUpperCase() + style.substr(1);
}
}
export default VueHtmlToPaper;
At last
Although this plug-in Vue
, it is js
and is suitable for any front-end environment. I hope to provide you with an idea.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。