vue实现手写签名
Vue 实现手写签名功能
使用 canvas 实现基础签名
在 Vue 项目中创建一个签名组件,使用 HTML5 的 canvas 元素作为画布。通过监听鼠标或触摸事件来捕获用户的绘制动作。
<template>
<div>
<canvas
ref="canvas"
@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,
};
},
mounted() {
this.setupCanvas();
},
methods: {
setupCanvas() {
const canvas = this.$refs.canvas;
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
this.ctx = canvas.getContext('2d');
this.ctx.strokeStyle = '#000';
this.ctx.lineWidth = 2;
this.ctx.lineCap = 'round';
},
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 canvas = this.$refs.canvas;
const rect = canvas.getBoundingClientRect();
return {
x: (e.clientX || e.touches[0].clientX) - rect.left,
y: (e.clientY || e.touches[0].clientY) - rect.top
};
},
clearCanvas() {
const canvas = this.$refs.canvas;
this.ctx.clearRect(0, 0, canvas.width, canvas.height);
},
saveSignature() {
const dataURL = this.$refs.canvas.toDataURL('image/png');
this.$emit('save', dataURL);
}
}
};
</script>
响应式设计优化
确保签名区域在不同设备上都能正常使用,特别是移动设备上的触摸支持。
<style scoped>
canvas {
border: 1px solid #000;
width: 100%;
height: 300px;
background-color: #fff;
touch-action: none;
}
button {
margin-top: 10px;
padding: 8px 16px;
}
</style>
使用第三方库简化实现
对于更复杂的签名需求,可以考虑使用专门的签名库如 vue-signature 或 signature_pad。

安装 signature_pad:
npm install signature_pad
在 Vue 中使用:

<template>
<div>
<canvas ref="canvas"></canvas>
<button @click="clear">清除</button>
<button @click="save">保存</button>
</div>
</template>
<script>
import SignaturePad from 'signature_pad';
export default {
mounted() {
this.signaturePad = new SignaturePad(this.$refs.canvas, {
backgroundColor: 'rgba(255, 255, 255, 0)',
penColor: 'rgb(0, 0, 0)'
});
this.resizeCanvas();
window.addEventListener('resize', this.resizeCanvas);
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeCanvas);
},
methods: {
resizeCanvas() {
const canvas = this.$refs.canvas;
const ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
canvas.getContext('2d').scale(ratio, ratio);
this.signaturePad.clear();
},
clear() {
this.signaturePad.clear();
},
save() {
if (this.signaturePad.isEmpty()) {
alert('请先签名');
return;
}
const dataURL = this.signaturePad.toDataURL();
this.$emit('save', dataURL);
}
}
};
</script>
保存签名数据
将签名数据转换为 base64 格式的图片数据,可以方便地提交到服务器或本地存储。
// 在父组件中接收签名数据
<signature-pad @save="handleSave" />
methods: {
handleSave(dataURL) {
// 提交到服务器或本地处理
console.log(dataURL);
// 或者转换为Blob对象
fetch(dataURL)
.then(res => res.blob())
.then(blob => {
const file = new File([blob], 'signature.png', { type: 'image/png' });
// 处理文件
});
}
}
移动端优化注意事项
确保在移动设备上有良好的触摸体验,需要注意以下几点:
- 禁用页面滚动防止签名时页面移动
- 处理触摸事件的多点触控问题
- 考虑不同设备的像素密度问题
- 增加签名区域的视觉反馈
// 防止触摸时页面滚动
document.addEventListener('touchmove', function(e) {
if (isDrawing) {
e.preventDefault();
}
}, { passive: false });
通过以上方法,可以在 Vue 项目中实现一个功能完善的手写签名组件,支持桌面和移动设备,并能够保存签名结果。






