vue實現(xiàn)打印指定組件內(nèi)容的示例詳解
前言
大家好,最近在做vue項目時使用到了print-js做打印指定組件內(nèi)容,并且還得切換紙張大小時做到自動適配布局的需求,其中遇到了一些問題及我的解題思路想給大家分享一下,希望日后能幫助到大家。
背景
大致需求是在頁面中提供一個多選框組,可以從中選擇打印哪些內(nèi)容,每個勾選項打印格式都是一樣的,不同的是每個勾選項獨占一頁,且響應式適配紙張大小,大致效果如下圖所示:


了解需求后,我們開始做開發(fā)準備工作!
引入print-js,并封裝打印函數(shù)
npm install print-js@1.3.1
usePrint.js
import printJS from 'print-js'
export const usePrint = () => {
printJS({
// 需要打印區(qū)域設置的Id
printable: 'print-area',
// 打印類型
type: 'html',
// 默認值為800,我們把把設置為100%
maxWidth: '100%',
// *代表應用所有樣式,默認值為null,如果不設置,打印窗口則會忽略所有樣式
targetStyles: ['*'],
});
上面主要注意點是注意點是修改maxWidth的默認值及設置targetStyles應用組件所寫的樣式。想要了解更多可參考:print-js文檔
封裝打印選擇器及打印內(nèi)容組件
引入插件后,我們先把打印的組件結(jié)構(gòu)先寫好,下面先把打印內(nèi)容選擇器結(jié)構(gòu)寫好
PrintSelector.vue
<template>
<div>
<!-- 這里是我們封裝的打印組件 -->
<PrintArea :data="printData" />
<el-checkbox :value="checkAll" @change="onCheckAllChange">全選</el-checkbox>
<div style="margin: 15px 0;"></div>
<el-checkbox-group v-model="checkedItems" @change="onCheckedChange">
<el-checkbox v-for="item in options" :label="item.id" :key="item.id">{{item.label}}</el-checkbox>
</el-checkbox-group>
<div style="margin: 15px 0;"></div>
<el-button @click="onPrint">打印</el-button>
</div>
</template>
<script>
import { usePrint } from './hooks/usePrint'
import PrintArea from './PrintArea.vue'
export default {
components: {
PrintArea
},
data() {
return {
checkedItems: [],
options: [
{ id: 1, label: '項目1' },
{ id: 2, label: '項目2' },
{ id: 3, label: '項目3' },
]
}
},
computed: {
checkAll() {
return this.checkedItems.length === this.options.length;
},
printData() {
return this.options.filter(item => this.checkedItems.includes(item.id))
}
},
methods: {
onCheckAllChange() {
if(this.checkAll) {
this.checkedItems = []
} else {
this.checkedItems = this.options.map(item => item.id)
}
},
onCheckedChange(val) {
this.checkedItems = val
},
onPrint() {
usePrint()
}
},
}
</script>
注意,上面我們把需要打印的組件PrintArea引入到了PrintSelector組件中,因為在調(diào)用printJS方法時需要通過id獲取頁面dom元素,所以需要組件的dom元素渲染到頁面中來,但是我們又不希望頁面中顯示打印的內(nèi)容,這里可以通過設置display: none把元素隱藏起來。但,隱藏后有一個需要注意的點,我們先把PrintArea組件寫出來,后面再進行講解。
PrintArea.vue
<template>
<div id="print-area" v-show="false">
<div class="item" v-for="item in data" :key="item.id">
<div class="head">頭部</div>
<div class="main">
<span class="text">{{ item.label }}</span>
</div>
<div class="footer">底部</div>
</div>
</div>
</template>
<script>
export default {
props: {
data: Array
}
}
</script>
這個組件就是我們需要打印的內(nèi)容,外部勾選需要打印的內(nèi)容后傳入當前組件即可,每一個item代表著一頁。我們回到前文提到的設置display:none時的問題,我們給id為print-area的打印內(nèi)容跟標簽隱藏了起來,如果這時選擇項目點擊打印后,會發(fā)現(xiàn)打印預覽窗口為空白?。?!
其實問題就是出現(xiàn)給打印區(qū)域設置了display:none,所以打印預覽窗口也把內(nèi)容隱藏了,解決辦法也簡單,就是給打印區(qū)域再套一層div,把v-show="false"設置在外層div上即可。
<template>
<div v-show="false">
<div id="print-area">
...省略其中代碼
</div>
</div>
</template>
這樣子打印窗口就能正常顯示內(nèi)容了。
我們下面通過一個小例子模擬打印預覽講解一下這個問題出現(xiàn)的原因:
demo.html
<body>
<div class="wrapper">
<!-- 打印區(qū)域 -->
<div id="print-area" style="display: none;">
<div class="item">111</div>
<div class="item">222</div>
</div>
</div>
<!-- 模擬打印預覽窗口 -->
<div id="print-window"></div>
<script>
window.onload = function() {
const printArea = document.getElementById('print-area')
const printWindow = document.getElementById('print-window')
// 把打印內(nèi)容放入打印預覽窗口
printWindow.appendChild(printArea)
}
</script>
</body>
上面我們實現(xiàn)了一個簡單的模擬打印流程,在打印區(qū)域的div上設置了display: none,所以調(diào)用appendChild放入模擬的打印窗口div下時,頁面并沒有內(nèi)容顯示,因為print-area樣式還是設置為隱藏。所以我們通過在外面增加一層用來設置隱藏樣式的div。這樣,我們獲取id為print-area的dom元素后,當前元素上沒有設置隱藏樣式,所以appendChild放到打印預覽窗口,就不會隱藏打印的內(nèi)容了!
頁面布局設計
我們在PrintArea.vue文件中先把樣式補上,看下效果
<style lang="scss" scoped>
#print-area {
background-color: deeppink;
.item {
display: flex;
flex-direction: column;
background-color: bisque;
.head {
text-align: center;
line-height: 100px;
font-weight: bold;
font-size: 36px;
background-color: azure;
}
.main {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.footer {
text-align: center;
line-height: 100px;
font-weight: bold;
font-size: 20px;
background-color: #eee;
}
}
}
</style>

我們的需求是根據(jù)每個item進行分頁打印,分頁實現(xiàn)可以直接在.item下設置page-break-after: always;樣式即可,但是還有一個需求是怎樣能夠讓item響應式適應紙張大小,占滿整個區(qū)域呢?第一想到的就是height: 100%,但,這樣就得保證每一層父組件的高度為頁面文檔的高度100%。好像不太理想,那設置每一頁item的高度為100vh呢?下圖可看出也并沒有達到想要的效果:

解決辦法是讓打印區(qū)域脫離文檔流,設置一個絕對定位
#print-area {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
.item {
height: 100%;
}
}
上面我們巧用絕對定位的上下左右距離都為0,使容器能撐滿整個紙張大小,最后給每一頁item繼承100%高度,這樣子布局就能夠適應各種紙張大小了,即使切換紙張也能夠達到撐滿整個容器的效果。
總結(jié)
以上我們主要是通過在打印內(nèi)容區(qū)域外設置v-show="false"來隱藏元素,使打印內(nèi)容不受隱藏影響,并通過一個小demo演示了問題出現(xiàn)的原因;接著我們通過在每個item下設置page-break-after: always;實現(xiàn)分頁;最后通過絕對定位使容器撐滿整個紙張,以達到切換紙張大小時也能撐滿整個容器的效果。
到此這篇關于vue實現(xiàn)打印指定組件內(nèi)容的示例詳解的文章就介紹到這了,更多相關vue打印指定組件內(nèi)容內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用vue初用antd 用v-model來雙向綁定Form表單問題
這篇文章主要介紹了使用vue初用antd 用v-model來雙向綁定Form表單問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
淺談vue中數(shù)據(jù)雙向綁定的實現(xiàn)原理
本篇文章主要介紹了淺談vue中數(shù)據(jù)雙向綁定的實現(xiàn)原理 ,主要使用v-model這個數(shù)據(jù)雙向綁定,有興趣的可以了解一下2017-09-09
vue中beforeRouteLeave實現(xiàn)頁面回退不刷新的示例代碼
這篇文章主要介紹了vue中beforeRouteLeave實現(xiàn)頁面回退不刷新的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-11-11
Vue3?實現(xiàn)驗證碼倒計時功能(刷新保持狀態(tài))
倒計時的運用場景是需要經(jīng)常用到的,但是根據(jù)業(yè)務的不同,好比手機驗證碼或者是郵箱驗證碼之類的,即使用戶跳轉(zhuǎn)到其它頁面或者刷新,再次回到登錄也,驗證碼的倒計時也得保持狀態(tài),下面通過本文給大家分享Vue3?驗證碼倒計時功能實現(xiàn),感興趣的朋友一起看看吧2022-08-08

