先看效果
*直接贴代码 *
使用签名的页面文件
<template>
<div class="about">
<h1>This is an about1 page</h1>
<div>
<span class="danger">*</span>
手写签名
</div>
<div class="disColumn">
<img
v-if="signvalue"
:src="signvalue"
class="nullSign"
@click="signCompentShow"
/>
<div v-else class="nullSign" @click="signCompentShow" />
</div>
<van-popup
v-model="signPopup"
close-on-popstate
>
<CostomSignToImg
v-show="signPopup"
ref="costomSignToImg"
:cancel="cancel"
:confirm="confirm"
/>
</van-popup>
</div>
</template>
<script>
import CostomSignToImg from "./CostomSignToImg.vue";
export default {
components:{
CostomSignToImg
},
data() {
return {
signvalue: false,
signPopup: false
};
},
methods: {
signCompentShow() {
console.log(111);
this.scrollTop = document.documentElement.scrollTop;
document.body.scrollTop = document.documentElement.scrollTop = 0;
setTimeout(() => {
this.signPopup = true;
}, 100);
},
cancel() {
document.body.scrollTop = document.documentElement.scrollTop = this.scrollTop;
this.signPopup = false;
},
confirm(img, a) {
document.body.scrollTop = document.documentElement.scrollTop = this.scrollTop;
this.signPopup = false;
console.log(img);
console.log(a);
this.signvalue = a;
this.blob = img;
},
},
};
</script>
<style>
.questItem {
padding: 0.625rem;
}
/* /deep/ .van-checkbox__label {
color: #f76a38;
} */
.nullSign {
background: #ebebeb;
height: 6.25rem;
width: 80vw;
margin: 0.625rem auto 0 auto;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
.searchLi:hover {
background-color: var(--color);
color: #fff;
}
.searchBox {
height: 9.375rem;
}
</style>
签名的组件
<template>
<div ref="container" class="container">
<canvas ref="myCanvas"></canvas>
<div class="control-ops control " ref="control" style="justify-content: space-around">
<van-button type="default" @click="onCancel">返回</van-button>
<van-button type="default" @click="clearArea">重新签名</van-button>
<van-button type="default" @click="onConfirm">确认</van-button>
</div>
</div>
</template>
<script>
export default {
props: ['confirm', 'cancel'],
data() {
return {
lastX: null,
lastY: null,
initialized: false,
orientation: "portrait",
isSigned:false,
};
},
mounted() {
var mql = window.matchMedia("(orientation: portrait)");
this.onMatchMeidaChange(mql);
mql.addListener(this.onMatchMeidaChange);
},
methods: {
getIsSigned(){
console.log(this.isSigned);
sessionStorage.setItem("isSigned",this.isSigned);
return this.isSigned;
},
onMatchMeidaChange(mql) {
if (mql.matches) {
this.orientation = "portrait";
} else {
this.orientation = "landscape";
}
this.$nextTick(this.init);
},
onConfirm() {
const c = this.$refs.myCanvas;
let image = c.toDataURL("image/png");
//得到生成后的签名base64位 url 地址
c.toBlob(async blob => {
const url = URL.createObjectURL(blob);
console.log(url, 'url');
if (this.orientation === "portrait") {
image = await this.rotateImage(url);
} else {
this.confirm(blob, image);
}
URL.revokeObjectURL(url);
});
this.clearArea()
},
onCancel() {
this.clearArea()
this.cancel();
},
clearArea() {
var c = this.$refs.myCanvas;
var ctx = c.getContext("2d");
// Use the identity matrix while clearing the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
},
rotateImage(url) {
let that =this
const width = window.innerWidth;
const height = window.innerHeight;
const canvas = document.createElement("canvas");
canvas.width = height;
canvas.height = width;
const ctx = canvas.getContext("2d");
ctx.rotate(-Math.PI / 2);
ctx.translate(-width, 0);
const image = new Image();
image.src = url;
image.setAttribute("crossOrigin", "anonymous");
return new Promise((resolve, reject) => {
image.onload = function () {
ctx.drawImage(this, 0, 0, width, height);
canvas.toBlob(async blob => {
that.confirm(blob, canvas.toDataURL("image/png"));
});
resolve(canvas.toDataURL("image/png"));
};
image.onerror = e => {
reject(e);
};
});
},
setControl() {
},
init() {
const width = window.innerWidth;
const height = window.innerHeight;
var mousePressed = false;
var c = this.$refs.myCanvas;
const ctx = c.getContext("2d");
const squareLen = Math.max(width, height);
c.setAttribute("width", `${width}px`);
c.setAttribute("height", `${height - 4}px`);
ctx.moveTo(0, 0);
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, squareLen, squareLen);
this.setControl();
var vm = this;
// 触摸屏
//签名开始
c.addEventListener(
"touchstart",
function (event) {
if (event.targetTouches.length == 1) {
event.preventDefault(); // 阻止浏览器默认事件,重要
var touch = event.targetTouches[0];
mousePressed = true;
vm.draw(
touch.pageX - this.offsetLeft,
touch.pageY - this.offsetTop,
false
);
this.isSigned = true;
sessionStorage.setItem("isSigned",this.isSigned);
}
},
false
);
//签名移动开始
c.addEventListener(
"touchmove",
function (event) {
if (event.targetTouches.length == 1) {
event.preventDefault(); // 阻止浏览器默认事件,重要
var touch = event.targetTouches[0];
if (mousePressed) {
vm.draw(
touch.pageX - this.offsetLeft,
touch.pageY - this.offsetTop,
true
);
this.isSigned = true
sessionStorage.setItem("isSigned",this.isSigned);
console.log(sessionStorage.getItem("isSigned"));
}
}
},
false
);
c.addEventListener(
"touchend",
function (event) {
if (event.targetTouches.length == 1) {
event.preventDefault(); // 阻止浏览器默认事件,防止手写的时候拖动屏幕,重要
// var touch = event.targetTouches[0];
mousePressed = false;
}
},
false
);
// 鼠标
c.onmousedown = function (event) {
mousePressed = true;
vm.draw(
event.pageX - this.offsetLeft,
event.pageY - this.offsetTop,
false
);
this.isSigned = true
};
c.onmousemove = function (event) {
if (mousePressed) {
vm.draw(
event.pageX - this.offsetLeft,
event.pageY - this.offsetTop,
true
);
this.isSigned = true
}
};
c.onmouseup = function () {
mousePressed = false;
this.isSigned = true
console.log(this.isSigned);
};
},
draw(x, y, isDown) {
var c = this.$refs.myCanvas;
var ctx = c.getContext("2d");
if (isDown) {
ctx.beginPath();
ctx.strokeStyle = "#666"; //颜色
ctx.lineWidth = 3; //线宽
ctx.lineJoin = "round";
ctx.moveTo(this.lastX, this.lastY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
}
this.lastX = x;
this.lastY = y;
}
}
};
</script>
<style >
canvas {
background: #fff;
}
.container {
position: relative;
}
.control {
position: absolute;
bottom: 0;
background: #ddd;
}
@media screen and (orientation: portrait) {
.control {
left: 0;
top: 0;
display: flex;
flex-direction: column;
height: 100vh;
}
.van-button {
transform: rotate(90deg);
}
}
@media screen and (orientation: landscape) {
.control {
left: 0;
width: 100%;
}
}
</style>
最终的签名图片是base64格式的
在父组件的 confirm函数里面我也有打印
终-----------