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


了解需求后,我們開始做開發(fā)準(zhǔn)備工作!
引入print-js,并封裝打印函數(shù)
npm install print-js@1.3.1
usePrint.js
import printJS from 'print-js'
export const usePrint = () => {
printJS({
// 需要打印區(qū)域設(shè)置的Id
printable: 'print-area',
// 打印類型
type: 'html',
// 默認(rèn)值為800,我們把把設(shè)置為100%
maxWidth: '100%',
// *代表應(yīng)用所有樣式,默認(rèn)值為null,如果不設(shè)置,打印窗口則會(huì)忽略所有樣式
targetStyles: ['*'],
});
上面主要注意點(diǎn)是注意點(diǎn)是修改maxWidth的默認(rèn)值及設(shè)置targetStyles應(yīng)用組件所寫的樣式。想要了解更多可參考: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: '項(xiàng)目1' },
{ id: 2, label: '項(xiàng)目2' },
{ id: 3, label: '項(xiàng)目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組件中,因?yàn)樵谡{(diào)用printJS方法時(shí)需要通過id獲取頁(yè)面dom元素,所以需要組件的dom元素渲染到頁(yè)面中來,但是我們又不希望頁(yè)面中顯示打印的內(nèi)容,這里可以通過設(shè)置display: none把元素隱藏起來。但,隱藏后有一個(gè)需要注意的點(diǎn),我們先把PrintArea組件寫出來,后面再進(jìn)行講解。
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>
這個(gè)組件就是我們需要打印的內(nèi)容,外部勾選需要打印的內(nèi)容后傳入當(dāng)前組件即可,每一個(gè)item代表著一頁(yè)。我們回到前文提到的設(shè)置display:none時(shí)的問題,我們給id為print-area的打印內(nèi)容跟標(biāo)簽隱藏了起來,如果這時(shí)選擇項(xiàng)目點(diǎn)擊打印后,會(huì)發(fā)現(xiàn)打印預(yù)覽窗口為空白!?。?/p>
其實(shí)問題就是出現(xiàn)給打印區(qū)域設(shè)置了display:none,所以打印預(yù)覽窗口也把內(nèi)容隱藏了,解決辦法也簡(jiǎn)單,就是給打印區(qū)域再套一層div,把v-show="false"設(shè)置在外層div上即可。
<template>
<div v-show="false">
<div id="print-area">
...省略其中代碼
</div>
</div>
</template>
這樣子打印窗口就能正常顯示內(nèi)容了。
我們下面通過一個(gè)小例子模擬打印預(yù)覽講解一下這個(gè)問題出現(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>
<!-- 模擬打印預(yù)覽窗口 -->
<div id="print-window"></div>
<script>
window.onload = function() {
const printArea = document.getElementById('print-area')
const printWindow = document.getElementById('print-window')
// 把打印內(nèi)容放入打印預(yù)覽窗口
printWindow.appendChild(printArea)
}
</script>
</body>
上面我們實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的模擬打印流程,在打印區(qū)域的div上設(shè)置了display: none,所以調(diào)用appendChild放入模擬的打印窗口div下時(shí),頁(yè)面并沒有內(nèi)容顯示,因?yàn)?code>print-area樣式還是設(shè)置為隱藏。所以我們通過在外面增加一層用來設(shè)置隱藏樣式的div。這樣,我們獲取id為print-area的dom元素后,當(dāng)前元素上沒有設(shè)置隱藏樣式,所以appendChild放到打印預(yù)覽窗口,就不會(huì)隱藏打印的內(nèi)容了!
頁(yè)面布局設(shè)計(jì)
我們?cè)?code>PrintArea.vue文件中先把樣式補(bǔ)上,看下效果
<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ù)每個(gè)item進(jìn)行分頁(yè)打印,分頁(yè)實(shí)現(xiàn)可以直接在.item下設(shè)置page-break-after: always;樣式即可,但是還有一個(gè)需求是怎樣能夠讓item響應(yīng)式適應(yīng)紙張大小,占滿整個(gè)區(qū)域呢?第一想到的就是height: 100%,但,這樣就得保證每一層父組件的高度為頁(yè)面文檔的高度100%。好像不太理想,那設(shè)置每一頁(yè)item的高度為100vh呢?下圖可看出也并沒有達(dá)到想要的效果:

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

