前言 纯前端实现对上传的pdf,进行盖章或签名后,并将处理后的pdf下载下来 目标
1 实现pdf上传与预览 2 手动签名,签名与印章的拖拽移动,实现在pdf上盖章与签名的效果 3 将盖章或签名的pdf文件进行绘制与下载
实现效果展示
所用的第三方依赖
- pdfh5 实现pdf文件的在线预览
- vue-esign 在画布上面签名,生成签名图片
- html2canvas html绘制图片
- jspdf 生成pdf、下载pdf
大致的逻辑 盖章与签名以图片的形式在pdf预览上进行拖拽,拖拽到pdf上 将拖拽的图片dragImg放到pdfViewer下,循环pdfViewer下的元素如果有dragImg
文件目录
DragImg组件:主要是实现图片的拖拽效果 inedx主文件:文件的上传预览等 SignImg组件:签名组件
接下来,一步一步去实现我们所需的效果
1 pdf文件上传
用el-upload
实现上传并监听before-upload
事件,在before-upload事件中限制文件大小、格式、类型等,若文件符合使用FileReader()
方法将文件转化为Base64,url接收Base64
数据(本文用的是Base64实现文预览效果)。
若你想pdf5中使用地址
方式,可以在上传成功之后将文件下载到项目的对应位置,并将地址信息保存在url属性中。
2 pdf在线预览
安装
npm i pdfh5 -S
引入
import Pdfh5 from "pdfh5" import "pdfh5/css/pdfh5.css"
使用
// 将pdf展示在id为preViewPdf的标签中
// pdfurl可以是文件地址,也可以是Base64(本文使用Base64)
this.pdfh5 = new Pdfh5('#preViewPdf', {
pdfurl: url, // '../../static/test.pdf'文件地址 或 Base64
maxZoom: 1, // 手势缩放最大倍数
// lazy:true,
// scrollEnable:true
})
其它可参考pdf5说明文档<https://www.npmjs.com/package/pdfh5>
3 手动签名
将签名封装到==SignImg==组件中 安装
npm i vue-esign -S
引入
import vueEsign from 'vue-esign'
components: {vueEsign}
使用vue-esign生成签名照
使用了<vueEsign></<vueEsign>
标签来调用 vue-esign 插件,并通过设置 width
和 height
属性来自定义签字区域的大小。isCrop
设置是否裁剪,lineWidth
画笔粗细,lineColor
画笔颜色。
<vueEsign ref="esign" style="width: 100%!important;height:83vh !important;margin-left: -0.3rem;" :isCrop="isCrop" :lineWidth="lineWidth" :lineColor="lineColor" :bgColor.sync="bgColor" >
</vueEsign>
签名完成通过handleGenerate
方法将签名转化为图片
<el-button type="primary" @click="handleGenerate">确定签名</el-button>
//生成签名图片..
handleGenerate() {
this.$refs.esign.generate().then(res => {
// res是一个图片的Base64格式
this.handleReset(); //清空画布
/**
业务逻辑
**
}).catch(err => {
console.log(err)
alert("请签名之后提交");
})
}
最终效果
上传印章
、盖章
以及签名照片的对象都是图片,通过拖拽图片
从而实现pdf的签名与盖章效果。
以下就不再对以上操作进行一一的详细展示,仅对说明如何实现图片拖拽效果
4 拖拽效果
封装一个DragImg
拖拽组件,将签名图片以及电子印章图片都放在这个组件中,从而实现签名与印章在pdf中的拖拽效果。
自定义拖拽指令drag
父元素绑定自定义指令,子元素展示图片
组件中的元素使用的是相对于父元素的绝对定位
<div v-drag="{ that }" onclick="" style="width: 100%;height: 100%;position: absolute;">
<img :class="'imgType_' + imgType" style="width: 100%;" :src="imgSrc" />
</div>
props: {
imgData: {
type: String,
default: ''
},
// ...一些其他辅助参数或方法
// 禁止拖拽方法
pauseHandle:{
type: Function,
value: null,
}
},
directives: {
// 自定义指令
drag: {
bind: function (el, binding) {
let oDiv = el; //当前元素
let that = binding.value.that;
oDiv.onmousedown = function (e) {
e.preventDefault();
// 下载过程中禁止拖拽
const isPause = that.pauseHandle() || false
if(isPause) return
let bw = document.body.clientWidth;
let bh = document.body.clientHeight;
//鼠标按下,计算当前元素距离可视区的距离
let disX = e.clientX - oDiv.offsetLeft;
let disY = e.clientY - oDiv.offsetTop;
// 计算两边坐标
document.onmousemove = function (e) {
let l = 0, t = 0;
// 拖动边界
if (e.clientX >= bw) {
l = bw - disX;
} else if (e.clientX <= 0) {
{
l = 0 - disX;
}
} else {
l = e.clientX - disX;
}
if (e.clientY >= bh) {
t = bh - disY;
} else if (e.clientY <= 0) {
t = 0 - disY;
} else {
t = e.clientY - disY;
}
//移动当前元素
oDiv.style.left = l + 'px';
oDiv.style.top = t + 'px';
};
// 鼠标停止移动时,事件移除
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
};
}
}
},
5 pdf下载
会用到的第三放插件是JsPDF
与html2canvas
在下载之前,先大致讲一下盖章与签字到pdf上的处理逻辑
1 将dragImg放到.pdfViewer
元素下,通过循环查询.pdfViewer下的元素当className == 'dragImg'
。
根据dragImg.style.top - pdfViewer.style.top
,计算图片应插入第几页,修改dragImg绝对定位后将dragImg插入相对应的.pageContainer元素下。签名或者印章在对应的页面中。
2 html2canvas
将每一页绘制成图片,通过addPage
创建空白页与addImage
添加图片,实现pdf的生成。
3 PDF.save
()下载生成的pdf。
先说明一下 一会儿会用到的几个元素的id
.pdfViewer 存放整个pdf .pageContainer pdf中的一页(多页就多个兄弟pageContainer) .dragImg 是你拖拽的签名或者印章图
创建印章并拖拽
let scrollt = document.querySelector(".pdfViewer").parentElement.parentElement.scrollTop;
var dragImg = Vue.extend(DragImg);
const app = new dragImg({
propsData: {
deleteDragImg: this.deleteDragImg, // 删除图片方法
imgData: imgData || this.signImgBase64, // 图片的Base64
isReuse: isReuse,
top: scrollt, //距离顶部的距离
imgType: type,
pauseHandle:this.pauseHandle // 是否禁用拖拽方法
},
ref: 'a'
}).$mount(document.createElement('div'));
// this.pdfh5 当前预览pdf
let currentNum = parseInt(this.pdfh5.pageNow[0].innerText);
this.pdfh5.pages[this.pdfh5.currentNum - 1].appendChild(app.$el)
this.pdfh5.pages[currentNum - 1].appendChild(app.$el)
// 将图片插入到.pdfViewer下
document.querySelector(".pdfViewer").appendChild(app.$el)
}
将签名或者印章方法对应的页面中
// 页面中有样式名为dragImg的,代表该页面有签名或者签章
// 有签名或签章就绘制页面
if (parentElement[i].className == 'dragImg') {
const promise = new Promise((resolve, reject) => {
let html = parentElement[i]
let ele = html.querySelector('#pic')
let eleImg = html.querySelector('#pic div')
let top = ele.style.top ? ele.style.top.split('px')[0] - 0 : 0
let topImg = eleImg.style.top ? eleImg.style.top.split('px')[0] - 0 : 0
let currentTop = top + topImg
if (currentTop > baseNum) {
console.log('第二页及以上')
let j = Math.ceil(currentTop / baseNum)
let pageContainer = document.querySelector(".pdfViewer .pageContainer" + j)
html.style.top = 0
ele.style.top = 0
eleImg.style.top = currentTop - baseNum * (j - 1) + 'px'
// 插入到对应页面中
pageContainer.appendChild(html)
resolve()
} else {
console.log('第一页')
let pageContainer = document.querySelector(".pdfViewer .pageContainer1")
pageContainer.appendChild(html)
resolve()
}
})
// 绘制图片
html2canvas(parent.children[i])
.then(function (canvas) {
// 绘制.pageContainer元素
if (parent.children[i].className != 'dragImg') {
let url = canvas.toDataURL();
let contentWidth = canvas.width
let contentHeight = canvas.height
let pageHeight = (contentWidth / 592.28) * 841.89
let leftHeight = contentHeight
let position = 0
let imgWidth = 595.28
let imgHeight = (592.28 / contentWidth) * contentHeight
let pageData = canvas.toDataURL('image/jpeg', 1.0)
// 第二页及以上
if (i != 0) PDF.addPage() // 添加空白页
if (leftHeight < pageHeight) {
PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight) //插入图片
} else {
if (leftHeight > 0) {
PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight) //插入图片
leftHeight -= pageHeight
position -= 841.89
}
}
}
if (length - 1 == i) {
setTimeout(()=>{
that.loading = false
// pdf下载
PDF.save(new Date().getTime() + '.pdf')
},1000)
}
});
完整代码下载地址:
<https://download.csdn.net/download/weixin_45291798/88580529?spm=1001.2014.3001.5503>
其他
依赖安装报错解决
npm install canvas@2.8.0 --ignore-scripts
只执行npm install canvas会报新的错误