起因
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
实现,实用于任何前端环境,心愿给大家提供一个思路。