移动端横屏、竖屏签名面板
原理:signature_pad插件,canvas
<template>
<div id="app">
<button @click="handleClick">点击签名</button>
<img :src="imgUrl" v-if="showImg" style="border:1px dashed #ccc;"/>
<div class="sign-box" v-show="showSignature">
<div class="bgc"></div>
<div class="main-box">
<span @click="cancelBgc" class="cancel">取消</span>
<p class="title">签名</p>
<p class="sub-title">请用正楷签下您的名字</p>
<div :style="{width:w,height:h}" class="canvass">
<canvas :id="uid" class="canvas" :data-uid="uid"></canvas>
</div>
<div id='reset' @click="clear">
<span>清除</span>
</div>
<div @click="saveSign" class="next">确认</div>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable */
import SignaturePad from 'signature_pad';
export default {
data() {
return {
showSignature: false,
showImg:false,
sig: () => { },
uid: 'canvas',
option: {
backgroundColor: 'rgb(255,255,255)',
penColor: 'rgb(0, 0, 0)',
minWidth: 0.8,
maxWidth: 4
},
w: '94.6%',
h: "240px",
}
},
methods: {
handleClick() {
this.showSignature = true;
this.$nextTick(() => {
this.draw();
})
},
// 签名
draw() {
var that = this;
var canvas = document.getElementById(that.uid);
that.sig = new SignaturePad(canvas, that.option);
window.addEventListener('resize', that.resizeCanvas);
that.resizeCanvas();
},
resizeCanvas() {
var that = this
var canvas = document.getElementById(that.uid);
var url;
var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
canvas.getContext('2d').scale(ratio, ratio);
that.clear()
!that.clearOnResize && url !== undefined && that.fromDataURL(url);
},
fromDataURL(url) {
var that = this;
that.sig.fromDataURL(url);
},
// 取消签名
cancelBgc() {
this.showSignature = false;
},
// 清除签名
clear() {
var that = this;
that.sig.clear();
},
isEmpty() {
var that = this;
return that.sig.isEmpty();
},
// 保存签名
saveSign() {
var that = this;
if (that.isEmpty()) {
alert('请用正楷签下您的名字');
return
}
var sign = {
signature: that.sig.toDataURL().split(',')[1]
}
that.imgUrl = "data:image/png;base64," + sign.signature;
that.showImg = true;
that.showSignature = false;
}
}
}
/* eslint-disable */
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin-top: 60px;
}
.canvass {
margin: auto;
background: #fff;
border: 1px dashed #e5e5e5;
border-radius: 8px;
margin-top: 17px;
position: relative;
}
#reset {
text-align: center;
font-size: 14px;
color: #666666;
margin-top: 26px;
margin-bottom: 47px;
}
#reset img {
width: 13px;
height: 13px;
}
canvas {
width: 100%;
height: 100%;
}
.sign-box {
position: fixed;
top: 0;
left: 0;
width: 100%;
min-height: 100vh;
}
.bgc {
opacity: 0.7;
background: #000000;
width: 100%;
height: 100%;
position: absolute;
top: 0;
z-index: 5;
}
.main-box {
height: 500px;
width: 100%;
background-color: #fff;
position: absolute;
bottom: 0;
z-index: 10;
}
.cancel {
position: absolute;
font-size: 18px;
color: #31A4FF;
left: 15px;
top: 16px;
}
.title {
text-align: center;
font-size: 18px;
color: #333333;
padding-top: 16px;
padding-bottom: 4px;
}
.sub-title {
font-size: 12px;
color: #999999;
text-align: center;
}
.next {
border: 1px solid #31A4FF;
height: 44px;
text-align: center;
line-height: 44px;
font-size: 18px;
color: #31A4FF;
background: #fff;
margin: 0 15px;
}
.footer {
position: fixed;
left: 0;
bottom: 0;
display: flex;
justify-content: space-between;
width: 100%;
}
.pre {
width: 28%;
margin-right: 1px;
border-top: 1px solid #d6d6d6;
color: #454545;
background: #fff;
}
.share {
width: 44%;
border-top: 1px solid #d6d6d6;
background: #66b9ff;
color: #fff;
}
.nextOne {
width: 28%;
color: #fff;
background: #31A4FF;
}
.commoncss {
height: calc(110rem / 24);
line-height: calc(110rem / 24);
font-size: 1.6rem;
text-align: center;
box-sizing: border-box;
margin-top: 1rem;
}
.hasLinkpre {
margin-top: 1rem;
background: #fff;
width: 50%;
height: calc(110rem / 24);
line-height: calc(110rem / 24);
font-size: 1.6rem;
text-align: center;
box-sizing: border-box;
color: #454545;
}
.hasLinknextone {
margin-top: 1rem;
background: #31A4FF;
width: 50%;
height: calc(110rem / 24);
line-height: calc(110rem / 24);
font-size: 1.6rem;
text-align: center;
box-sizing: border-box;
color: #fff;
}
</style>
效果图:


横屏签名:
<template>
<div id="app">
<div class="content">
<div class="btn" @click='toSign()'>点击此处签名</div>
<img :src="'data:image/png;base64,'+appntSign" alt="" v-show="appntSign" id="signImg">
</div>
<div id="signContent" class='signBox' v-show="showSign">
<div class="canvass">
<canvas :id="uid" class="canvas" :data-uid="uid"></canvas>
</div>
<div class='footer'>
<span @click="clear()">重签</span>
<span @click="keepSign()" :class='{active:canSaveBtn}'>保存签名</span>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable */
import SignaturePad from 'signature_pad';
export default {
props: {
showSignPage: {
type: Boolean,
default: false
},
relation: {
type: String
},
sigOption: {
type: Object,
default: () => {
return {
backgroundColor: 'rgb(255,255,255)',
penColor: 'rgb(0, 0, 0)'
}
}
},
w: {
type: String,
default: '90%'
},
h: {
type: String,
default: '250px'
},
clearOnResize: {
type: Boolean,
default: false
}
},
data() {
return {
sig: () => { },
option: {
backgroundColor: 'rgb(255,255,255)',
penColor: 'rgb(0, 0, 0)'
},
uid: '',
signPerson: '投保人',
time: 0,
contNo: '',
num: '',
getdata: "",
buttomShow: false,
showSign: false,
appntSign: '',
canSaveBtn: false,
needRotate: ''// 0 不旋转 1旋转
}
},
created() {
var _this = this
this.uid = 'canvas' + _this._uid
var sigOptions = Object.keys(_this.sigOption)
for (var item of sigOptions) {
_this.option[item] = _this.sigOption[item]
}
},
watch: {
// 险种信息监听
showSignPage: {
handler: function (val, oldVal) {
this.resizeCanvas()
},
// 深度观察
deep: true
}
},
methods: {
checkbox() {
if (!this.appntSign) {
this.buttomShow = false;
Dialog.alert({
message: '请签名'
}).then(() => {
// on close
});
return
}
this.buttomShow = !this.buttomShow;
},
draw() {
var _this = this
var canvas = document.getElementById(_this.uid)
_this.sig = new SignaturePad(canvas, _this.option)
window.addEventListener('resize', _this.resizeCanvas)
_this.resizeCanvas()
canvas.addEventListener('touchstart', function (e) {
e.preventDefault()
_this.canSave()
})
_this.setMark('请在此处使用正楷签名')
},
resizeCanvas() {
var _this = this
var canvas = document.getElementById(_this.uid)
var url
var ratio = Math.max(window.devicePixelRatio || 1, 1)
canvas.width = canvas.offsetWidth * ratio
canvas.height = canvas.offsetHeight * ratio
canvas.getContext('2d').scale(ratio, ratio)
_this.clear()
!_this.clearOnResize && url !== undefined && _this.fromDataURL(url)
},
clear() {
var _this = this
_this.sig.clear()
this.canSaveBtn = false
},
canSave() {
this.canSaveBtn = true
},
toSign() {
this.appntSign = ''
this.showSign = true
this.buttomShow = false;
this.$nextTick(() => {
this.draw()
})
},
keepSign() { //保存签名
var _this = this
if (_this.isEmpty()) {
return
}
_this.appntSign = _this.sig.toDataURL().split(',')[1]
_this.showSign = false
clearInterval(this.time)
let id = _this.setWatermark('请在此处使用正楷签名');
let rotate = document.getElementById(id).style.transform
console.log(rotate)
document.getElementById(id).style.display = 'none'
let img = document.getElementById('signImg')
debugger
if (!rotate) {
img.style.height = '65px'
img.style.width = ''
img.style.marginBottom = '-20px'
img.style.marginLeft = '15px'
img.style.transform = ''
_this.needRotate = '0'
} else {
img.style.width = '65px'
img.style.height = ''
img.style.marginBottom = '-50px'
img.style.marginLeft = '35px'
img.style.transform = 'rotate(-90deg)'
_this.needRotate = '1'
}
},
cancel() {
this.$emit('callback')
},
save(format) {
var _this = this
var str = "";
if (!_this.appntSign) {
Dialog.alert({
message: '请签名'
}).then(() => {
// on close
});
return
}
let params = {
contNo: _this.contNo,
status: "02",
imgBase64: _this.appntSign,
index: "0",
faceImageFlag: sessionStorage.getItem("faceImageFlag"),
needRotate: _this.needRotate
}
questionnaireSubmit(params).then(result => {
if (result && result.errorCode === "1") {
_this.getdata = result.responseBody;
str = _this.getdata.appntName + "," + _this.getdata.contNo + "," + _this.getdata.mainRiskName + "," + _this.getdata.addRiskName + "," + _this.getdata.statusLabel + "," + _this.getdata.visitDate + "," + _this.getdata.visitStatus + "," + _this.num;
sessionStorage.setItem("camera", true); //true (正在进行中) false (下一次重新开始)
_this.$router.push({ path: "end", query: { postdata: str } })
} else {
_this.$toast(result.errorMessage)
}
})
.catch(rej => {
console.log("签名", rej)
})
_this.buttomShow = !_this.buttomShow
},
fromDataURL(url) {
var _this = this
_this.sig.fromDataURL(url)
},
isEmpty() {
var _this = this
return _this.sig.isEmpty()
},
undo() {
var _this = this
var data = _this.sig.toData()
if (data) {
data.pop()
_this.sig.fromData(data)
}
},
setWatermark(str) { // 水印背景设置
let id = '1.23452384164.123412416';
if (document.getElementById(id) !== null) {
document.body.removeChild(document.getElementById(id));
}
//创建一个画布
let can = document.createElement('canvas');
//设置画布的长宽
can.width = 500;
can.height = 100;
let cans = can.getContext('2d');
//旋转角度
// cans.rotate(-15 * Math.PI / 180);
cans.font = '40px Vedana';
//设置填充绘画的颜色、渐变或者模式
cans.fillStyle = 'rgba(200, 200, 200, 0.40)';
//设置文本内容的当前对齐方式
cans.textAlign = 'left';
//设置在绘制文本时使用的当前文本基线
cans.textBaseline = 'Middle';
//在画布上绘制填色的文本(输出的文本,开始绘制文本的X坐标位置,开始绘制文本的Y坐标位置)
cans.fillText(str, can.width / 8, can.height / 2);
let div = document.createElement('div');
div.id = id;
div.style.pointerEvents = 'none';
div.style.position = 'fixed';
div.style.zIndex = '100000';
let e = document.getElementsByClassName('canvas')[0]
let height = e.offsetHeight
let width = e.offsetWidth
console.log(width)
console.log(height)
if (width > height) { // 横屏
div.style.width = width + 'px';
div.style.height = height + 'px';
div.style.top = '20px';
div.style.left = '15px';
} else { // 竖屏
div.style.width = height + 'px';
div.style.height = width + 'px';
div.style.top = 20 + (height - width) / 2 + 'px';
div.style.right = 15 - (height - width) / 2 + 'px';
div.style.transform = 'rotate(90deg)'
}
div.style.background = 'url(' + can.toDataURL('image/png') + ') center center no-repeat';
document.body.appendChild(div);
return id;
},
setMark(str) { // 显示水印背景
let id = this.setWatermark(str);
this.time = setInterval(() => {
if (document.getElementById(id) === null) {
id = this.setWatermark(str);
}
}, 500);
window.onresize = () => {
this.setWatermark(str);
};
}
},
mounted() {
}
}
/* eslint-disable */
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin-top: 60px;
}
.content {
background: #fff;
padding: 20px 23px 35px;
min-height: 200px;
}
.content h4 {
font-size: 16px;
margin-bottom: 20px;
color: #333;
}
.content p {
color: #666;
font-size: 14px;
}
.content div.btn {
width: 150px;
height: 40px;
line-height: 40px;
text-align: center;
background: #31A4FF;
color: #fff;
font-size: 16px;
margin: 15px auto 40px;
}
.content span {
color: #666;
font-size: 14px;
}
/* 竖屏情况下 */
@media screen and (orientation:portrait) {
.signBox {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
background: #fff;
z-index: 10000;
}
.canvass {
padding: 20px 15px;
width: 100%;
height: 90%;
box-sizing: border-box;
}
canvas {
width: 100%;
height: 100%;
border: 1px dashed #333;
border-radius: 8px;
}
.footer {
text-align: center;
height: 10%;
padding: 10px 0;
writing-mode: vertical-lr;
box-sizing: border-box;
}
.footer span {
border: 1px solid #999;
color: #999;
height: 30vw;
width: 40px;
display: inline-block;
line-height: 40px;
font-size: 16px;
text-align: center;
background: #fff;
margin-top: -40px;
margin-left: 24vw;
transform: rotate(90deg)
}
.footer span:last-child {
background: #ccc;
color: #fff;
border-color: transparent;
margin-left: 34vw;
}
.footer span.active {
background: #31A4FF;
color: #fff;
}
}
/* 横屏情况下 */
@media screen and (orientation:landscape) {
.signBox {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
background: #fff;
z-index: 10000;
}
.canvass {
float: left;
padding: 12px 10px;
width: 90%;
height: 100%;
box-sizing: border-box;
}
canvas {
width: 100%;
height: 100%;
border: 1px dashed #333;
border-radius: 5px;
}
.footer {
text-align: center;
float: right;
width: 10%;
height: 100%;
padding: 0 5px;
box-sizing: border-box;
writing-mode: vertical-lr;
}
.footer span {
border: 1px solid #999;
color: #999;
width: 22px;
height: 30vh;
display: inline-block;
line-height: 22px;
font-size: 8px;
text-align: center;
background: #fff;
margin-top: calc (13vh - 20px);
}
.footer span:last-child {
background: #ccc;
color: #fff;
border-color: transparent;
margin-top: 14vh;
}
.footer span.active {
background: #31A4FF;
color: #fff;
}
}
.take-photo {
margin: auto;
}
.take-photo #submit {
background: #31A4FF;
color: #fff;
font-size: 16px;
text-align: center;
margin: 15px auto;
width: 90%;
height: 100%;
line-height: 1.5;
}
.take-photo #submit2 {
background: #E0E0E0;
color: #fff;
font-size: 16px;
text-align: center;
margin: 15px auto;
width: 90%;
width: 90%;
height: 100%;
line-height: 1.5;
}
.mobile-ts {
color: #4c4c4c;
font-size: 12px;
padding: 10px 10px 0px 25px;
position: relative;
text-indent: 25px;
}
.imgSpan {
position: absolute;
left: 25px;
text-indent: 0;
}
.mobile-ts .imgSpan img {
width: 16px;
height: 16px;
}
</style>

浙公网安备 33010602011771号