起因
Vue
我的项目中,有一个打印(导出 pdf
)需要,于是网上搜查了几个插件包含vue 插件
和js 插件
,要么太重不够轻量级,要么性能不够欠缺,最终没有一款插件符合要求。
通过搜查插件和材料的过程,发现打印原理并不难,于是尝试本人写一个插件,成果十分棒,而且十分轻量级。
效果图
上面是理论我的项目中的局部打印截图:
应用
应用过程中,只须要传入要打印的 dom
元素即可,vue
中应用 ref
,须要留神的是要打印的元素css
款式不依赖于其余元素,必须是能够独立的展现的,比方,上面实例中 resume-container
元素不能依赖 box
,否则会造成打印时款式局部失落的状况。
示例如下:
<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>
源代码
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;
最初
此插件尽管是在 Vue
中开发,然而是纯 js
实现,实用于任何前端环境,心愿给大家提供一个思路。