项目需要,要在移动端实现手写签名转换成图片,需要用到canvas实现,canvas实在是没学过,只能硬着头皮上,借助万能的网络,废了几千个脑细胞,终于把功能实现了,现在记录以下,希望可以帮助其他码友
展示:
页面布局
<div class="sign_page" v-show="isShowSign" @touchmove.prevent="">
<div class="canvas_page" >
<div style="float:left;font-size:20px;margin-top:10px;margin-left:10px;">填写签名</div>
<div @click="closeSign" style="float:right;margin-top:10px;margin-right:20px;"><van-icon name="close" size="30" /></div>
<div class="handCenter">
<canvas id="canvasMy"></canvas>
</div>
</div>
<div class="button_line">
<van-button size="small" color="#00B9AA" style="margin-right:20px;width:90px;" @click.stop="clearArea">重写</van-button>
<van-button color="#00B9AA" size="small" style="margin-right:20px;width:90px;" @click="toNextStep">确认并提交</van-button>
</div>
</div>
css样式
.sign_page{
position:fixed;
top:0;
left:0;
height:100%;
width: 100%;
background: rgba(19, 18, 18,0.7);
z-index: 1111;
}
.canvas_page{
width:80%;
background: #ffffff;
height:60%;
margin-top: 90px;
margin-left: 10%;
box-sizing: border-box;
overflow: hidden;
.handCenter {
overflow: hidden;
// max-width:60vw;
width: 100%;
height:90%;
// margin:0 auto;
margin-top: 50px;
box-shadow: 0 2px 4px rgba(0,0,0,.25);
box-sizing: border-box;
}
}
.button_line{
display: flex;
justify-content: center;
margin: 0 auto;
width: 80%;
align-items: center;
background: #ffffff;
padding:40px 0 20px 0;
}
/*重写的按钮*/
.reWriteBtn{
padding: 0.1rem 0.2rem!important;
font-size:18px;
text-align: center;
}
代码实现业务逻辑
1、弹出签名弹窗时要初始化画布,设置好画布的监听器
//填写签名
sign(){
this.isShowSign=true;
this.$nextTick(() => {
let canvas = document.getElementById('canvasMy');
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
let node = document.getElementsByClassName('handCenter')[0];
let rect = node.getBoundingClientRect();
let winW = rect.width;
let winH = rect.height
canvas.width = winW;
canvas.height = winH;
this.Init()
});
},
Init() {
this.isShowSign=true;
this.canvas.addEventListener(
'touchstart',
(event)=> {
if (event.targetTouches.length == 1) {
event.preventDefault(); // 阻止浏览器默认事件,重要
var touch = event.targetTouches[0];
this.touchPressed = true;
let x = event.changedTouches[0].clientX;
let y = event.changedTouches[0].clientY;
//this.draw(touch.pageX - this.canvas.offsetLeft, touch.pageY - this.canvas.offsetTop, false);
this.draw(x - this.canvas.offsetLeft, y - this.canvas.offsetTop, false);
}
},
false
);
this.canvas.addEventListener(
'touchmove',
(event) =>{
if (event.targetTouches.length == 1) {
event.preventDefault(); // 阻止浏览器默认事件,重要
var touch = event.targetTouches[0];
let x = event.changedTouches[0].clientX;
let y = event.changedTouches[0].clientY;
if (this.touchPressed) {
//this.draw(touch.pageX - this.canvas.offsetLeft, touch.pageY - this.canvas.offsetTop, true);
this.draw(x - this.canvas.offsetLeft, y - this.canvas.offsetTop, true);
}
}
},
false
);
this.canvas.addEventListener(
'touchend',
(event)=> {
if (event.targetTouches.length == 1) {
event.preventDefault(); // 阻止浏览器默认事件,防止手写的时候拖动屏幕,重要
this.touchPressed = false;
}
},
false
);
},
2、签名完成周点击确认按钮把签名转换成图片
根据各自后台的要求将签名转换成相应的格式传给后台,保存在服务器上
//点击确认按钮
toNextStep:debounce(function () {
let res = this.ifDraw();
if(res){
this.$message.warning('请写下你的签名')
return
}
this.$confirm('确认当前的签名无误且清晰?', '提示')
.then(() => {
this.saveImage();
})
.catch(action => {
});
},1000),
//保存为图片
saveImage() {
let oCanvas = document.getElementById("canvasMy");
let imgBase64 = oCanvas.toDataURL();
this.imgsrc = imgBase64;
// let url = this.canvas.toDataURL(); //此时图片为Base64格式
let file = this.dataURLtoFile(imgBase64);
//此时图片为Base64格式
const form = new FormData();
form.append('file',file)//向formdata里面存放键值
this.$api.uploadPictureCheck(form).then(res=>{
if(res.data.success==true){
this.signPic = res.data.filePath;
this.sure();
}else{
Toast('签名上传失败')
}
}).catch(err=>{
})
},
//转成 File 对象将画布转为文件流,可以用于后续的上传
dataURLtoFile(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
// 这里的 'share.png' 是自定义的文件名
return new File([u8arr], 'sign' + '.png',{ type: mime });
},
draw(x, y, isDown) {
let ctx = this.ctx
if (isDown) {
ctx.beginPath();
ctx.strokeStyle = this.strokeStyle;
ctx.lineWidth = this.lineWidth;
ctx.lineJoin = "round";
ctx.moveTo(this.lastX, this.lastY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
}
this.lastX = x; this.lastY = y;
},
clearArea(){
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
},
//判断是否绘制签名
ifDraw(){
var blank = document.createElement('canvas');
blank.width = this.canvas.width;
blank.height = this.canvas.height;
return this.canvas.toDataURL() == blank.toDataURL();
},
//Base64格式转成图片
dataURLtoBlob(dataurl) {
var arr = dataurl.split(',')
var mime = arr[0].match(/:(.*?);/)[1]
var bstr = atob(arr[1])
var n = bstr.length
var u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], {
type: mime
})
},
这样基本就可以实现,主要难点在将签名转换成图片传给后台保存