安装
cnpm install vue3-print-nb
cnpm install html2canvas
cnpm install jspdf
代码
<div class="print-preview">
<div class="flex f-end exportBtn">
<a-button v-print="print">打印</a-button>
<a-button class="ml-10" @click="exportToPDF('printFrom')">导出PDF</a-button>
</div>
<div class="print-container">
<div id="printFrom">
<h3 class="title">员工入职登记表</h3>
<div class="flex f-between">
<a-form-item label="公司">{{ formModel.rosterFromDetailResp?.companyStr }}</a-form-item>
<a-form-item label="部门">{{ formModel.rosterFromDetailResp?.departmentStr }}</a-form-item>
<a-form-item label="岗位">{{ formModel.rosterFromDetailResp?.positionStr }}</a-form-item>
<a-form-item label="入职日期">{{ formModel.rosterFromDetailResp?.joinWorkDate }}</a-form-item>
</div>
</div>
</div>
</div>
import { ref, reactive, toRefs, onMounted } from 'vue'
import print from 'vue3-print-nb'
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
const print = ref({
id: 'printFrom',//这里的id就是上面我们的打印区域id,实现指哪打哪
// popTitle: '', // 打印配置页上方的标题
extraHead: '', // 最上方的头部文字,附加在head标签上的额外标签,使用逗号分割
preview: false, // 是否启动预览模式,默认是false
previewTitle: '', // 打印预览的标题
previewPrintBtnLabel: '', // 打印预览的标题下方的按钮文本,点击可进入打印
zIndex: 20002, // 预览窗口的z-index,默认是20002,最好比默认值更高
})
const exportToPDF = async (elementId) => {
const element = document.getElementById(elementId);
// 使用 html2canvas 将 DOM 转换为 canvas 图像
const canvas = await html2Canvas(element, {
scale: 2,
logging: true, // 开启日志以便调试
ignoreElements: (el) => el.style.display === 'none' // 忽略隐藏元素
});
const imgData = canvas.toDataURL('image/jpeg', 0.7); // 使用 JPEG 格式
// 获取 canvas 的宽度和高度(单位:像素)
const imgWidth = canvas.width;
const imgHeight = canvas.height;
// 定义转换比例因子(从像素到毫米)
const ratio = 25.4 / 96; // 1 英寸 = 25.4 mm, 默认屏幕分辨率为 96 dpi
// 计算页面尺寸(单位:毫米)
const pdfWidth = imgWidth * ratio;
const pdfHeight = imgHeight * ratio;
// 创建一个新的 jsPDF 实例,动态设置页面大小
const orientation = pdfWidth > pdfHeight ? 'l' : 'p'; // 根据宽高比选择方向
const pdf = new JsPDF({
orientation,
unit: 'mm',
format: [pdfWidth, pdfHeight]
});
// 添加白色背景,避免阴影
pdf.setFillColor(255, 255, 255);
pdf.rect(0, 0, pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight(), 'F');
// 添加图像到 PDF 文档
// 添加图像到 PDF 文档时,确保宽度和高度与 PDF 页面完全匹配
pdf.addImage(imgData, 'PNG', 0, 0, pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight());
// 保存 PDF 文件
pdf.save('员工入职登记表.pdf');
}
<style scoped lang="less">
.print-preview {
padding: 10px 0;
position: relative;
.exportBtn {
position: sticky;
top: 10px;
margin-right: 40px;
}
}
.print-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
#printFrom {
text-align: center;
padding: 20px;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
page-break-inside: avoid;
th,
td {
font-size: 14px;
font-weight: normal;
min-width: 100px;
max-width: 156px;
white-space: wrap;
text-align: center;
padding: 0 4px;
height: 27px;
}
}
/* 定义单选按钮组的基本样式 */
.radio-group {
display: flex;
align-items: center;
}
/* 隐藏原始的单选按钮 */
input[type="radio"] {
display: none;
}
/* 定义标签的基础样式 */
label {
position: relative;
padding-left: 25px;
margin-right: 20px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
}
/* 创建空心圆圈作为未选中的状态 */
label::before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
margin-right: 8px;
position: absolute;
left: 0;
top: 0;
background-color: white;
border: 1px solid #ccc;
border-radius: 50%;
transition: all 0.3s ease;
}
/* 创建实心圆圈作为选中的状态 */
input[type="radio"]:checked+label::after {
content: "";
display: block;
width: 10px;
height: 10px;
position: absolute;
left: 3px;
top: 3px;
background-color: #3498db;
border-radius: 50%;
transition: all 0.3s ease;
}
@media print {
.title {
text-align: center;
}
#printFrom {
box-shadow: none;
th,
td {
min-width: 100px;
max-width: 156px;
white-space: wrap;
}
}
input[type="radio"]:checked+label::after {
content: "";
display: block;
width: 10px;
height: 10px;
position: absolute;
left: 3px;
top: 3px;
background-color: #3498db;
border-radius: 50%;
transition: all 0.3s ease;
-webkit-print-color-adjust: exact !important; //强调背景颜色
color-adjust: exact !important; //强调背景颜色
}
}
.ant-form-item {
margin-bottom: 0px !important;
}
</style>