前言
在现代 Web 应用开发中,打印功能是一个常见但又容易被忽视的需求。无论是电商后台的订单打印、企业管理系统的报表输出,还是教育平台的证书生成,都离不开页面打印功能的支持。对于 Vue 3 项目而言,vue3-print-nb 插件无疑是一个值得关注的选择。
本文将从实际应用角度出发,系统性地介绍 vue3-print-nb 插件的完整使用方法,涵盖从环境搭建到高级技巧的全流程内容。无论你是 Vue 3 新手还是老手,都能从中获得有价值的信息。
一、插件简介与优势
vue3-print-nb 是一款专为 Vue 3 设计的打印功能插件,它以自定义指令的形式提供简洁、高效的打印解决方案。与其他打印方案相比,该插件具有以下显著优势:
轻量级设计:插件体积小巧,对项目性能影响极低,无需引入庞大的第三方依赖。
操作简便 :通过简单的 v-print 指令即可实现复杂打印功能,学习成本极低。
功能完备:支持局部打印、全局打印、URL 打印、打印预览等多种场景,几乎涵盖所有常见打印需求。
高度可定制:提供丰富的配置选项和回调函数,开发者可以根据业务需求灵活调整打印行为。
Vue 3 原生支持:专为 Vue 3 设计,充分利用 Composition API 的优势,与现代 Vue 项目完美融合。
在实际项目中,该插件已被广泛应用于订单管理、数据报表、证书打印、合同输出等多个业务场景,获得了良好的社区反馈。
二、环境准备与安装
2.1 前置条件
在使用 vue3-print-nb 之前,请确保你的开发环境满足以下要求:
Node.js 版本建议 14.x 或更高版本,以确保最佳的兼容性。项目应基于 Vue 3 构建,推荐使用 Vite 作为构建工具以获得更好的开发体验。
2.2 安装命令
通过 npm 或 yarn 即可轻松完成插件安装。打开终端,进入项目根目录,执行以下命令:
使用 npm 安装:
bash
npm install vue3-print-nb --save
或者使用 yarn 安装:
bash
yarn add vue3-print-nb
如果你的项目仍在使用 Vue 2,则需要安装对应的 Vue 2 版本插件:
bash
npm install vue-print-nb --save
本文将重点介绍 Vue 3 版本的使用方法,Vue 2 版本的基本用法类似,将在后续章节简要说明差异。
2.3 TypeScript 类型支持
对于使用 TypeScript 的项目,可能需要在类型定义文件中添加模块声明,以避免 IDE 报类型错误。在 src 目录下找到或创建 env.d.ts 文件,添加以下内容:
typescript
declare module "vue3-print-nb";
这样 TypeScript 编译器就能正确识别插件的导入类型。
三、项目集成配置
插件安装完成后,需要在项目入口文件中进行注册配置。vue3-print-nb 支持全局注册和局部注册两种方式,开发者可以根据实际需求选择合适的方案。
3.1 全局注册(推荐)
全局注册是最常用的方式,一次配置即可在项目任意组件中使用打印功能。在项目入口文件(通常是 main.js 或 main.ts)中添加以下代码:
javascript
import { createApp } from 'vue'
import App from './App.vue'
import print from 'vue3-print-nb'
const app = createApp(App)
app.use(print)
app.mount('#app')
这种配置方式的优势在于简单快捷,所有组件无需额外导入即可使用 v-print 指令。对于大多数项目而言,全局注册是首选方案。
3.2 局部注册
在某些特定场景下,你可能希望打印功能只在特定组件中使用,此时可以选择局部注册方式。在目标组件中按需引入:
javascript
import print from 'vue3-print-nb'
export default {
directives: {
print
}
}
或者在 <script setup> 语法糖中使用:
javascript
<script setup>
import print from 'vue3-print-nb'
defineOptions({
directives: {
print
}
})
</script>
局部注册虽然增加了每个组件的配置工作量,但可以有效控制插件功能的作用范围,提升代码的可维护性。在大型项目中,建议对打印功能的使用场景进行统一规划。
四、基础使用详解
完成插件注册后,让我们通过实际示例来了解其核心用法。vue3-print-nb 提供了三种基本的打印模式:整页打印、局部打印和 URL 打印。
4.1 整页打印
整页打印是最简单的使用方式,只需在按钮上添加 v-print 指令,无需任何参数,即可打印整个页面:
html
<template>
<div>
<h1>订单详情页面</h1>
<p>订单编号:DD20240315001</p>
<p>下单时间:2024-03-15 10:30:00</p>
<p>订单金额:¥299.00</p>
<!-- 打印按钮 -->
<button v-print>打印订单</button>
</div>
</template>
这种模式适用于简单的内容预览或不需要精细控制打印范围的场景。点击按钮后,浏览器将打开系统打印对话框,显示整个页面的打印预览。
4.2 局部范围打印
局部打印是实际项目中最常用的功能,它允许我们精确控制只打印页面中的特定区域。通过为打印区域设置唯一 ID,然后在 v-print 指令中指定该 ID 即可实现:
html
<template>
<div>
<!-- 页面上的其他内容不会被打印 -->
<div class="page-header">
<h1>系统管理后台</h1>
<p>欢迎使用后台管理系统</p>
</div>
<!-- 打印区域 -->
<div id="printArea">
<h2>用户信息表</h2>
<table>
<thead>
<tr>
<th>序号</th>
<th>姓名</th>
<th>部门</th>
<th>职位</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>张三</td>
<td>技术部</td>
<td>高级工程师</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>产品部</td>
<td>产品经理</td>
</tr>
</tbody>
</table>
</div>
<!-- 打印按钮 -->
<button v-print="'#printArea'">打印表格</button>
</div>
</template>
注意 v-print 指令的值需要使用引号包裹,并且以井号(#)开头表示 ID 选择器。也可以传入对象形式的配置参数,实现更精细的控制:
javascript
export default {
data() {
return {
printOptions: {
id: 'printArea',
popTitle: '用户信息表'
}
}
}
}
html
<button v-print="printOptions">打印表格</button>
4.3 URL 打印
除了打印页面内容,插件还支持打印指定 URL 的页面内容。这在需要打印独立页面或第三方页面时非常有用:
html
<button v-print="printUrlOptions">打印指定页面</button>
javascript
export default {
data() {
return {
printUrlOptions: {
url: 'http://localhost:8080/print-template',
beforeOpenCallback() {
console.log('即将打开打印工具')
},
openCallback() {
console.log('打印工具已打开')
},
closeCallback() {
console.log('打印工具已关闭')
}
}
}
}
}
需要特别注意的是,出于浏览器安全策略的限制,被打印的 URL 必须与当前页面遵循相同的同源策略,否则可能会被浏览器阻止。
五、完整 API 参数文档
vue3-print-nb 提供了丰富的配置选项,下面是完整的 API 参数说明文档。这些参数可以通过 v-print 指令以对象形式传入,实现各种定制化的打印效果。
| 参数名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
id |
局部打印的区域 ID,必填项 | String | --- | --- |
standard |
HTML 文档类型 | String | html5 / loose / strict | html5 |
extraHead |
插入到 <head> 标签内的额外元素,多个用逗号分隔 |
String | --- | --- |
extraCss |
额外的 CSS 样式表路径,多个用逗号分隔 | String | --- | --- |
popTitle |
打印页面的标题内容 | String | --- | --- |
openCallback |
打印工具成功打开时的回调函数 | Function | 返回 Vue 实例 | --- |
closeCallback |
关闭打印工具成功时的回调函数 | Function | 返回 Vue 实例 | --- |
beforeOpenCallback |
调用打印工具之前的回调函数 | Function | 返回 Vue 实例 | --- |
url |
要打印的指定 URL(不能与 id 同时设置) | String | --- | --- |
asyncUrl |
通过 resolve() 返回 URL 的异步函数 | Function | --- | --- |
preview |
是否开启打印预览模式 | Boolean | true/false | false |
previewTitle |
预览窗口的标题 | String | --- | '打印预览' |
previewPrintBtnLabel |
预览窗口中打印按钮的文本 | String | --- | '打印' |
zIndex |
预览窗口的 CSS z-index 值 | Number | --- | 20002 |
previewBeforeOpenCallback |
预览工具启动前的回调函数 | Function | 返回 Vue 实例 | --- |
previewOpenCallback |
预览工具完全打开后的回调函数 | Function | 返回 Vue 实例 | --- |
5.1 标准文档类型参数
standard 参数用于指定打印输出的 HTML 文档类型,不同类型会影响浏览器的解析和渲染方式:
- html5:HTML5 标准类型,兼容性最好,推荐作为默认选项
- loose:宽松类型,允许存在一些非标准的 HTML 结构
- strict:严格类型,要求严格的 HTML 文档结构
javascript
printOptions: {
id: 'printArea',
standard: 'html5'
}
5.2 样式扩展参数
extraCss 和 extraHead 参数允许在打印时注入额外的样式和元素,这在需要特殊打印效果时非常有用:
javascript
printOptions: {
id: 'printArea',
// 引入外部 CSS 样式表
extraCss: 'https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.min.css',
// 添加额外的 head 元素
extraHead: '<meta http-equiv="Content-Language" content="zh-cn"/>'
}
5.3 回调函数详解
插件提供了完整的生命周期回调函数,帮助开发者在打印过程的各个阶段执行自定义逻辑:
javascript
printOptions: {
id: 'printArea',
popTitle: '打印预览',
// 预览窗口加载前触发
previewBeforeOpenCallback() {
console.log('预览窗口正在加载中...')
},
// 预览窗口完全打开后触发
previewOpenCallback() {
console.log('预览窗口已显示')
},
// 调用系统打印对话框前触发
beforeOpenCallback(vue) {
// 可以访问 Vue 实例的响应式数据
vue.printLoading = true
console.log('准备打开打印对话框')
},
// 打印对话框成功打开时触发
openCallback(vue) {
vue.printLoading = false
console.log('打印对话框已打开')
},
// 打印对话框关闭时触发
closeCallback(vue) {
console.log('打印操作已结束')
}
}
六、实战应用示例
理论知识的掌握需要通过实践来巩固。下面我们通过几个实际项目中的典型场景,展示 vue3-print-nb 的完整使用流程。
6.1 订单打印功能
订单打印是企业级应用中最常见的需求之一,下面演示一个完整的订单打印组件实现:
html
<template>
<div class="order-detail">
<!-- 页面其他内容 -->
<div class="order-nav">
<el-button @click="goBack">返回列表</el-button>
<el-button type="primary" v-print="printOptions" :loading="printLoading">
打印订单
</el-button>
</div>
<!-- 订单基本信息 -->
<el-card class="order-info">
<template #header>
<span>订单信息</span>
</template>
<el-descriptions :column="2" border>
<el-descriptions-item label="订单编号">
{{ orderData.orderNo }}
</el-descriptions-item>
<el-descriptions-item label="下单时间">
{{ orderData.createTime }}
</el-descriptions-item>
<el-descriptions-item label="收货人">
{{ orderData.receiverName }}
</el-descriptions-item>
<el-descriptions-item label="联系电话">
{{ orderData.receiverPhone }}
</el-descriptions-item>
<el-descriptions-item label="收货地址" :span="2">
{{ orderData.receiverAddress }}
</el-descriptions-item>
</el-descriptions>
</el-card>
<!-- 订单商品列表 -->
<el-card class="order-products">
<template #header>
<span>商品明细</span>
</template>
<el-table :data="orderData.products" border stripe>
<el-table-column prop="name" label="商品名称" />
<el-table-column prop="spec" label="规格" />
<el-table-column prop="price" label="单价" width="100">
<template #default="{ row }">
¥{{ row.price.toFixed(2) }}
</template>
</el-table-column>
<el-table-column prop="quantity" label="数量" width="80" />
<el-table-column prop="subtotal" label="小计" width="100">
<template #default="{ row }">
¥{{ row.subtotal.toFixed(2) }}
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 打印区域(隐藏的 DOM 结构) -->
<div v-show="false">
<div id="orderPrintArea">
<div class="print-header">
<h1>销售订单</h1>
<p>单据编号:{{ orderData.orderNo }}</p>
<p>打印时间:{{ currentDate }}</p>
</div>
<div class="print-section">
<h3>客户信息</h3>
<p>收货人:{{ orderData.receiverName }}</p>
<p>电话:{{ orderData.receiverPhone }}</p>
<p>地址:{{ orderData.receiverAddress }}</p>
</div>
<div class="print-section">
<h3>商品清单</h3>
<table class="print-table">
<thead>
<tr>
<th>序号</th>
<th>商品名称</th>
<th>规格</th>
<th>单价</th>
<th>数量</th>
<th>小计</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in orderData.products" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.spec }}</td>
<td>¥{{ item.price.toFixed(2) }}</td>
<td>{{ item.quantity }}</td>
<td>¥{{ item.subtotal.toFixed(2) }}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" class="text-right">合计金额:</td>
<td class="text-bold">¥{{ orderData.totalAmount.toFixed(2) }}</td>
</tr>
</tfoot>
</table>
</div>
<div class="print-footer">
<p>备注:{{ orderData.remark || '无' }}</p>
<p class="signature">客户签名:________________</p>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const printLoading = ref(false)
const currentDate = computed(() => {
return new Date().toLocaleString('zh-CN')
})
const orderData = ref({
orderNo: 'DD2024031500001',
createTime: '2024-03-15 10:30:00',
receiverName: '王小明',
receiverPhone: '138****8888',
receiverAddress: '北京市朝阳区建国路88号SOHO现代城A座1201室',
remark: '请勿暴力轻放',
totalAmount: 599.00,
products: [
{ name: 'iPhone 15 Pro', spec: '256GB 深空黑', price: 7999, quantity: 1, subtotal: 7999 },
{ name: 'MagSafe 充电器', spec: '官方标配', price: 299, quantity: 1, subtotal: 299 },
{ name: 'AirPods Pro 2', spec: 'USB-C充电盒', price: 1899, quantity: 1, subtotal: 1899 }
]
})
const printOptions = ref({
id: 'orderPrintArea',
popTitle: '订单打印',
beforeOpenCallback() {
printLoading.value = true
},
openCallback() {
printLoading.value = false
},
closeCallback() {
console.log('打印任务已完成')
}
})
const goBack = () => {
// 返回上一页逻辑
}
</script>
<style scoped>
/* 页面显示样式 */
.order-detail {
padding: 20px;
}
.order-nav {
margin-bottom: 20px;
display: flex;
gap: 10px;
}
/* 打印样式 - 关键部分 */
@media print {
/* 隐藏非打印元素 */
.order-nav,
.order-info,
.order-products {
display: none !important;
}
/* 打印区域样式 */
#orderPrintArea {
padding: 20px;
font-size: 14px;
line-height: 1.6;
}
.print-header {
text-align: center;
margin-bottom: 30px;
border-bottom: 2px solid #333;
padding-bottom: 20px;
}
.print-header h1 {
font-size: 24px;
margin-bottom: 10px;
}
.print-section {
margin-bottom: 25px;
}
.print-section h3 {
background: #f5f5f5;
padding: 8px 10px;
margin-bottom: 10px;
}
.print-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.print-table th,
.print-table td {
border: 1px solid #333;
padding: 8px;
text-align: center;
}
.print-table th {
background: #eee;
}
.text-right {
text-align: right;
}
.text-bold {
font-weight: bold;
}
.print-footer {
margin-top: 50px;
border-top: 1px solid #ddd;
padding-top: 20px;
}
.signature {
margin-top: 60px;
text-align: right;
}
}
</style>
这个示例展示了订单打印的完整实现,包括数据展示、打印配置和打印专用样式的定义。注意在 <style> 中使用 @media print 规则来控制打印时的样式显示。
6.2 异步数据打印处理
在实际业务中,打印内容往往需要从后端接口获取。vue3-print-nb 本身不直接支持异步数据,但我们可以结合 Vue 的响应式系统和 nextTick 来实现:
html
<template>
<div>
<el-button type="primary" @click="handlePrint">打印报表</el-button>
<!-- 模拟点击触发器 -->
<div id="printTrigger" v-print="printOptions" style="display: none"></div>
<!-- 打印区域 -->
<div id="reportPrintArea" style="display: none">
<h1>数据报表</h1>
<p>生成时间:{{ reportData.generateTime }}</p>
<table>
<thead>
<tr>
<th>指标</th>
<th>数值</th>
<th>同比</th>
</tr>
</thead>
<tbody>
<tr v-for="item in reportData.items" :key="item.id">
<td>{{ item.name }}</td>
<td>{{ item.value }}</td>
<td>{{ item.change }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup>
import { ref, nextTick } from 'vue'
const reportData = ref({
generateTime: '',
items: []
})
const printOptions = ref({
id: 'reportPrintArea',
popTitle: '数据报表'
})
async function fetchReportData() {
// 模拟接口请求
const response = await fetch('/api/report')
const data = await response.json()
reportData.value = {
generateTime: new Date().toLocaleString('zh-CN'),
items: data.items
}
}
async function handlePrint() {
// 显示打印区域
document.getElementById('reportPrintArea').style.display = 'block'
// 等待 DOM 更新
await nextTick()
// 触发打印
document.getElementById('printTrigger').click()
}
</script>
6.3 打印预览功能
打印预览是用户体验的重要环节,让用户在正式打印前确认内容无误。vue3-print-nb 内置了预览功能,只需简单配置即可启用:
html
<template>
<div>
<el-button type="primary" v-print="previewOptions">
预览并打印
</el-button>
<div id="previewPrintArea">
<h2>合同文件预览</h2>
<div class="contract-content">
<p>甲方:________________</p>
<p>乙方:________________</p>
<p>签订日期:{{ currentDate }}</p>
<div class="contract-body">
<p>第一条 合同金额</p>
<p>本合同总金额为人民币(大写):__________元整</p>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const currentDate = computed(() => {
return new Date().toLocaleDateString('zh-CN')
})
const previewOptions = {
id: 'previewPrintArea',
popTitle: '合同文档',
// 开启预览模式
preview: true,
// 预览窗口标题
previewTitle: '打印预览 - 合同文档',
// 预览窗口中打印按钮的文本
previewPrintBtnLabel: '确认打印',
// 预览窗口的层级
zIndex: 20002,
// 预览加载前回调
previewBeforeOpenCallback() {
console.log('正在加载预览窗口...')
},
// 预览加载完成回调
previewOpenCallback() {
console.log('预览窗口已打开')
},
// 打印对话框打开前回调
beforeOpenCallback() {
console.log('即将打开系统打印对话框')
},
// 打印对话框关闭回调
closeCallback() {
console.log('打印任务已结束')
}
}
</script>
七、打印样式深度优化
打印效果的好坏很大程度上取决于 CSS 样式的控制。以下是一些实用的打印样式优化技巧。
7.1 分页控制
通过 CSS 可以精确控制打印内容的分页行为:
css
@media print {
/* 避免在表格中间分页 */
table {
page-break-inside: avoid;
}
/* 标题总是在新页开始 */
h2, h3 {
page-break-after: avoid;
page-break-inside: avoid;
}
/* 强制在元素前分页 */
.new-page {
page-break-before: always;
}
/* 避免在链接和图片后分页 */
a, img {
page-break-after: avoid;
}
}
7.2 页边距与纸张设置
使用 @page 规则可以控制打印的页面布局:
css
@media print {
@page {
size: A4; /* 纸张大小:A4、Letter、Legal 等 */
margin: 15mm 20mm; /* 页边距 */
}
/* 首页可以有不同的边距 */
@page :first {
margin-top: 10mm;
}
}
7.3 页眉页脚处理
默认情况下,浏览器会打印 URL 和页码。如果想去除这些默认元素,可以使用 extraHead 参数:
javascript
const printOptions = {
id: 'printArea',
extraHead: `
<style>
@page { margin: 10mm; }
body { -webkit-print-color-adjust: exact; }
</style>
`
}
7.4 图片与颜色处理
确保打印时保持原始颜色和布局:
css
@media print {
/* 强制保留背景颜色和图片 */
* {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
}
/* 确保图片完整显示 */
img {
max-width: 100% !important;
page-break-inside: avoid;
}
}
八、常见问题与解决方案
8.1 打印区域为空或不完整
问题表现:点击打印后,预览区域显示空白或内容不完整。
原因分析:这通常是由于打印区域的 DOM 结构在打印时还未渲染完成,或者 CSS 样式导致元素被隐藏。
解决方案:
javascript
// 确保在 DOM 渲染完成后执行打印
import { nextTick } from 'vue'
async function handlePrint() {
// 显示打印区域
printAreaVisible.value = true
// 等待 Vue 完成 DOM 更新
await nextTick()
// 额外等待确保样式渲染
await new Promise(resolve => setTimeout(resolve, 100))
// 执行打印
document.getElementById('printTrigger').click()
}
8.2 样式在打印时丢失
问题表现:屏幕显示正常,但打印出来的效果与预览差异很大。
原因分析:打印样式可能没有正确应用,或者被其他样式覆盖。
解决方案:
css
/* 在打印区域组件内部添加 !important 确保优先级 */
@media print {
.print-area * {
font-family: 'SimSun', serif !important;
color: #000 !important;
background: #fff !important;
}
}
8.3 跨域 URL 无法打印
问题表现:打印外部 URL 时内容为空或报错。
原因分析:浏览器的同源策略限制不允许跨域 iframe 打印。
解决方案:需要后端支持 CORS,或者将外部内容先获取到本地再打印:
javascript
async function printRemoteContent() {
try {
// 通过代理获取远程内容
const response = await fetch('/api/proxy?url=' + encodeURIComponent(targetUrl))
const html = await response.text()
// 将内容注入到本地 DOM
document.getElementById('printArea').innerHTML = html
// 执行打印
document.getElementById('printTrigger').click()
} catch (error) {
console.error('获取打印内容失败', error)
}
}
8.4 打印时出现空白页
问题表现:打印内容正常,但最后多出一页空白页。
原因分析:通常是由于页面底部存在空白区域或隐藏元素导致的。
解决方案:
css
@media print {
html, body {
height: auto;
overflow: visible;
}
/* 确保没有多余的空白元素 */
.no-print {
display: none !important;
}
}
8.5 Vue 2 与 Vue 3 版本差异
| 功能 | Vue 2 版本 | Vue 3 版本 |
|---|---|---|
| 安装命令 | npm install vue-print-nb |
npm install vue3-print-nb |
| 引入方式 | import Print from 'vue-print-nb' |
import print from 'vue3-print-nb' |
| 全局注册 | Vue.use(Print) |
app.use(print) |
| 局部注册 | directives: { print } |
directives: { print } |
| API 参数 | 相同 | 相同 |
九、进阶使用技巧
9.1 批量打印实现
在实际业务中,可能需要一次性打印多个文档。可以通过循环调用或动态设置打印 ID 来实现:
html
<template>
<div>
<el-button @click="printMultiple">批量打印选中订单</el-button>
<el-checkbox-group v-model="selectedOrders">
<el-checkbox
v-for="order in orderList"
:key="order.id"
:label="order.id"
>
{{ order.orderNo }}
</el-checkbox>
</el-checkbox-group>
<template v-for="order in orderList" :key="order.id">
<div :id="'print-' + order.id" class="print-template">
<h1>订单:{{ order.orderNo }}</h1>
<!-- 订单内容 -->
</div>
</template>
</div>
</template>
<script setup>
import { ref } from 'vue'
const selectedOrders = ref([])
const orderList = ref([
{ id: 1, orderNo: 'DD001', content: '...' },
{ id: 2, orderNo: 'DD002', content: '...' },
{ id: 3, orderNo: 'DD003', content: '...' }
])
async function printMultiple() {
if (selectedOrders.value.length === 0) {
alert('请先选择要打印的订单')
return
}
for (const orderId of selectedOrders.value) {
await new Promise(resolve => {
const options = {
id: `print-${orderId}`,
beforeOpenCallback: resolve,
closeCallback: () => console.log(`订单 ${orderId} 打印完成`)
}
// 动态设置 v-print
const btn = document.createElement('button')
btn.setAttribute('v-print', JSON.stringify(options))
document.body.appendChild(btn)
btn.click()
document.body.removeChild(btn)
})
}
}
</script>
9.2 打印参数动态配置
根据不同业务场景动态调整打印配置:
javascript
function getPrintOptions(type) {
const baseOptions = {
id: 'printArea',
beforeOpenCallback() {
console.log('开始打印')
}
}
// 根据类型扩展配置
switch (type) {
case 'invoice':
return {
...baseOptions,
popTitle: '发票打印',
extraCss: '/styles/invoice-print.css'
}
case 'report':
return {
...baseOptions,
popTitle: '报表打印',
preview: true,
previewTitle: '报表预览'
}
case 'label':
return {
...baseOptions,
popTitle: '标签打印',
extraHead: '<style>@page { size: 100mm 50mm; margin: 0; }</style>'
}
default:
return baseOptions
}
}
9.3 打印前的数据预处理
在实际项目中,打印前往往需要对数据进行格式化处理:
javascript
function preprocessPrintData(data) {
return {
...data,
// 格式化日期
createTime: formatDate(data.createTime),
// 格式化金额
amount: formatCurrency(data.amount),
// 添加水印标识
watermark: `打印时间:${new Date().toLocaleString()}`
}
}
function formatDate(date) {
return new Date(date).toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
})
}
function formatCurrency(amount) {
return `¥${Number(amount).toFixed(2)}`
}
十、总结与最佳实践
通过本文的详细介绍,相信你已经对 vue3-print-nb 插件有了全面深入的理解。在实际项目中应用这个插件时,以下几点建议值得关注:
合理规划打印区域:将需要打印的内容和页面交互元素分开,使用独立的 DOM 区域来组织打印内容,便于样式控制和功能维护。
注重打印样式设计:打印效果与屏幕显示同样重要,应该针对打印场景设计专门的样式,确保输出的文档专业美观。
完善错误处理:打印功能可能因为各种原因失败,应该添加适当的错误处理和用户提示,提升用户体验。
测试多浏览器兼容性:虽然现代浏览器对打印的支持已经很好,但仍建议在不同浏览器上进行测试,确保打印效果一致。
保持性能优化:避免在打印区域中放置大量图片或复杂动画,这会严重影响打印性能。
vue3-print-nb 作为 Vue 3 生态中优秀的打印插件,以其简洁的 API、丰富的功能和良好的扩展性,值得在实际项目中推广应用。如果你有任何问题或建议,欢迎在评论区交流讨论。
参考链接:
- 官方 GitHub 仓库:https://github.com/Power-kxLee/vue3-print-nb
- NPM 插件地址:https://www.npmjs.com/package/vue3-print-nb
相关技术栈:Vue 3、Element Plus、Vite、TypeScript