前言
在移动端开发中,手写签名功能是一个非常常见的需求。本文将手把手教你如何在uniapp中使用vue3的组合式API封装一个手写签名弹出框组件。通过封装,我们可以在项目中轻松复用该组件,提高开发效率。
实现步骤
1. 组件设计与功能
-
手写签名:用户可以在
canvas
上绘制签名。 -
重置功能:清除画布内容,重新签名。
-
保存功能:将签名保存为图片,并生成
base64
或临时文件路径。 -
预览功能:预览签名图片。
-
横屏适配:支持横屏模式,提升用户体验。
2. 组件代码实现
2.1 模板部分 (template
)
<template>
<view class="signature-container">
<!-- 画布区域 -->
<canvas
canvas-id="signatureCanvas"
class="signature-canvas"
disable-scroll="true"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
></canvas>
<!-- 操作按钮 -->
<view class="button-group">
<button @click="handleReset">重置</button>
<button @click="handleSave">保存</button>
<button @click="handlePreview">预览</button>
</view>
</view>
</template>
2.2 脚本部分 (script
)
<script>
export default {
data() {
return {
ctx: null, // canvas 上下文
points: [], // 存储绘制路径点
canvasWidth: 0, // 画布宽度
canvasHeight: 0, // 画布高度
tempFilePath: "", // 临时文件路径
};
},
mounted() {
this.initCanvas();
},
methods: {
// 初始化画布
initCanvas() {
const query = uni.createSelectorQuery().in(this);
query
.select(".signature-canvas")
.boundingClientRect((rect) => {
this.canvasWidth = rect.width;
this.canvasHeight = rect.height;
this.ctx = uni.createCanvasContext("signatureCanvas", this);
this.ctx.lineWidth = 4; // 设置线条宽度
this.ctx.lineCap = "round"; // 设置线条端点样式
this.ctx.lineJoin = "round"; // 设置线条交点样式
})
.exec();
},
// 触摸开始
handleTouchStart(e) {
const startX = e.touches[0].x;
const startY = e.touches[0].y;
this.points.push({ x: startX, y: startY });
this.ctx.beginPath();
this.ctx.moveTo(startX, startY);
},
// 触摸移动
handleTouchMove(e) {
const moveX = e.touches[0].x;
const moveY = e.touches[0].y;
this.points.push({ x: moveX, y: moveY });
if (this.points.length >= 2) {
const point1 = this.points[this.points.length - 2];
const point2 = this.points[this.points.length - 1];
this.ctx.moveTo(point1.x, point1.y);
this.ctx.lineTo(point2.x, point2.y);
this.ctx.stroke();
this.ctx.draw(true);
}
},
// 触摸结束
handleTouchEnd() {
this.points = [];
},
// 重置画布
handleReset() {
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.ctx.draw(true);
this.tempFilePath = "";
},
// 保存签名
handleSave() {
if (this.points.length === 0) {
uni.showToast({ title: "请先签名", icon: "none" });
return;
}
uni.canvasToTempFilePath({
canvasId: "signatureCanvas",
success: (res) => {
this.tempFilePath = res.tempFilePath;
uni.showToast({ title: "保存成功", icon: "success" });
this.$emit("save", res.tempFilePath); // 触发保存事件
},
fail: (err) => {
console.error("保存失败", err);
},
});
},
// 预览签名
handlePreview() {
if (!this.tempFilePath) {
uni.showToast({ title: "请先保存签名", icon: "none" });
return;
}
uni.previewImage({
urls: [this.tempFilePath],
});
},
},
};
</script>
2.3 样式部分 (style
)
<style scoped>
.signature-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.signature-canvas {
width: 100%;
height: 300px;
border: 1px solid #ccc;
background-color: #fff;
}
.button-group {
margin-top: 20px;
display: flex;
justify-content: space-around;
width: 100%;
}
button {
flex: 1;
margin: 0 10px;
}
</style>
3. 使用示例
在父组件中引入并使用该签名组件:
<template>
<view>
<signature-component @save="handleSave"></signature-component>
</view>
</template>
<script>
import SignatureComponent from "@/components/SignatureComponent.vue";
export default {
components: {
SignatureComponent,
},
methods: {
handleSave(tempFilePath) {
console.log("签名图片路径:", tempFilePath);
// 可以将路径上传至服务器或进行其他处理
},
},
};
</script>
4. 注意事项
-
横屏适配:如果需要横屏模式,可以在
pages.json
中配置pageOrientation: "landscape"
。 -
性能优化:对于复杂的签名路径,建议限制路径点的数量,避免内存占用过高。
-
兼容性:确保在微信开发者工具中测试,并检查真机运行效果。
通过以上实现,您可以快速在 uni-app
中封装一个功能完善的手写签名组件,并适配微信小程序平台。希望这篇文章能帮助你解决问题!如果有其他疑问,欢迎在评论区留言讨论!