vue实现页面签字
使用 canvas 实现电子签名
在 Vue 中可以通过原生 canvas 或第三方库实现签名功能。以下是一个基于 canvas 的基础实现方案:
<template>
<div class="signature-container">
<canvas
ref="signaturePad"
@mousedown="startDrawing"
@mousemove="draw"
@mouseup="stopDrawing"
@mouseleave="stopDrawing"
@touchstart="startDrawing"
@touchmove="draw"
@touchend="stopDrawing"
></canvas>
<button @click="clearCanvas">清除</button>
<button @click="saveSignature">保存</button>
</div>
</template>
<script>
export default {
data() {
return {
isDrawing: false,
lastX: 0,
lastY: 0,
canvas: null,
ctx: null
}
},
mounted() {
this.initCanvas()
},
methods: {
initCanvas() {
this.canvas = this.$refs.signaturePad
this.ctx = this.canvas.getContext('2d')
this.resizeCanvas()
// 设置画布样式
this.ctx.strokeStyle = '#000'
this.ctx.lineWidth = 2
this.ctx.lineCap = 'round'
this.ctx.lineJoin = 'round'
},
resizeCanvas() {
const container = this.canvas.parentElement
this.canvas.width = container.offsetWidth
this.canvas.height = container.offsetHeight * 0.7
},
startDrawing(e) {
this.isDrawing = true
const pos = this.getPosition(e)
this.lastX = pos.x
this.lastY = pos.y
},
draw(e) {
if (!this.isDrawing) return
const pos = this.getPosition(e)
this.ctx.beginPath()
this.ctx.moveTo(this.lastX, this.lastY)
this.ctx.lineTo(pos.x, pos.y)
this.ctx.stroke()
this.lastX = pos.x
this.lastY = pos.y
},
stopDrawing() {
this.isDrawing = false
},
getPosition(e) {
const rect = this.canvas.getBoundingClientRect()
return {
x: (e.clientX || e.touches[0].clientX) - rect.left,
y: (e.clientY || e.touches[0].clientY) - rect.top
}
},
clearCanvas() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
},
saveSignature() {
const image = this.canvas.toDataURL('image/png')
this.$emit('signature-saved', image)
}
}
}
</script>
使用第三方库 signature_pad
对于更专业的签名需求,推荐使用 signature_pad 库:
npm install signature_pad
<template>
<div>
<canvas ref="signatureCanvas"></canvas>
<button @click="clear">清除</button>
<button @click="save">保存</button>
</div>
</template>
<script>
import SignaturePad from 'signature_pad'
export default {
data() {
return {
signaturePad: null
}
},
mounted() {
this.initSignaturePad()
},
methods: {
initSignaturePad() {
const canvas = this.$refs.signatureCanvas
canvas.width = canvas.offsetWidth
canvas.height = canvas.offsetHeight
this.signaturePad = new SignaturePad(canvas, {
minWidth: 1,
maxWidth: 3,
penColor: '#000',
backgroundColor: 'rgb(255, 255, 255)'
})
},
clear() {
this.signaturePad.clear()
},
save() {
if (this.signaturePad.isEmpty()) {
alert('请先签名')
return
}
const dataURL = this.signaturePad.toDataURL()
this.$emit('signature-saved', dataURL)
}
}
}
</script>
移动端适配方案
为确保在移动设备上的良好体验,需要添加以下样式和配置:
<style scoped>
canvas {
border: 1px solid #ddd;
background-color: #fff;
touch-action: none; /* 禁用浏览器默认手势 */
}
.signature-container {
width: 100%;
max-width: 600px;
margin: 0 auto;
}
button {
margin-top: 10px;
padding: 8px 16px;
background: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
</style>
保存签名数据
签名通常需要以图片形式保存或上传:
methods: {
async uploadSignature() {
const blob = await this.dataURLToBlob(this.signaturePad.toDataURL())
const formData = new FormData()
formData.append('signature', blob, 'signature.png')
try {
const response = await axios.post('/api/upload-signature', formData)
console.log('上传成功', response.data)
} catch (error) {
console.error('上传失败', error)
}
},
dataURLToBlob(dataURL) {
const arr = dataURL.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], { type: mime })
}
}
签名验证功能
添加签名是否为空验证:
methods: {
validateSignature() {
if (this.signaturePad.isEmpty()) {
return {
valid: false,
message: '请提供有效签名'
}
}
return {
valid: true,
message: ''
}
}
}






