签名页的效果如图下所示:
封装的组件代码如下所示:
<template><view><view class="wrapper"><view class="handBtn"><button @click="handleReset" class="delBtn">清除</button><button @click="handleSubmit" class="saveBtn">保存</button><button @click="handleBack" class="subBtn">返回</button></view><view class="handCenter"><canvas class="handWriting" :disable-scroll="true" @touchstart="touchstart" @touchmove="touchmove"@touchend="touchend" canvas-id="myCanvas" :style="{width:width +'px',height:height +'px'}"></canvas><!--用于旋转图片的canvas容器--><canvas style="position: absolute" :style="{ width: height+'px', height: width+'px' }"canvas-id="myCanvas2"></canvas></view><view class="handRight"><view class="handTitle">请签名</view></view></view></view>
</template><script>export default {data() {return {ctx: '', //绘图图像points: [], //路径点集合,width: 0, //绘图宽度height: 0, //绘图高度hasSign: false, //是否已签名isInit: false, //是否已触摸};},mounted() {const _self = this;this.ctx = uni.createCanvasContext('myCanvas', this); //创建绘图对象//设置画笔样式this.ctx.lineWidth = 4;this.ctx.lineCap = 'round';this.ctx.lineJoin = 'round';uni.getSystemInfo({success: function(res) {_self.width = res.windowWidth - 95;_self.height = res.windowHeight - 30;}});},methods: {/*** 触摸开始,获取到起点 */touchstart: function(e) {if (!this.isInit) {this.isInit = true;this.handleReset();};let startX = e.changedTouches[0].x;let startY = e.changedTouches[0].y;let startPoint = {X: startX,Y: startY};this.points.push(startPoint);//每次触摸开始,开启新的路径this.ctx.beginPath();},/*** 触摸移动,获取到路径点*/touchmove: function(e) {let moveX = e.changedTouches[0].x;let moveY = e.changedTouches[0].y;let movePoint = {X: moveX,Y: moveY};this.points.push(movePoint); //存点let len = this.points.length;if (len >= 2) {this.draw(); //绘制路径}},/*** 触摸结束,将未绘制的点清空防止对后续路径产生干扰*/touchend: function() {this.points = [];this.ctx.draw(true);},/*** 绘制笔迹* 1.为保证笔迹实时显示,必须在移动的同时绘制笔迹* 2.为保证笔迹连续,每次从路径集合中区两个点作为起点(moveTo)和终点(lineTo)* 3.将上一次的终点作为下一次绘制的起点(即清除第一个点)*/draw: function() {let point1 = this.points[0];let point2 = this.points[1];this.points.shift();this.ctx.moveTo(point1.X, point1.Y);this.ctx.lineTo(point2.X, point2.Y);this.ctx.stroke();this.ctx.draw(true);this.hasSign = true;},//清空画布handleReset: function() {this.ctx.clearRect(0, 0, this.width, this.height);this.ctx.draw(true);this.hasSign = false;},/***保存签名*/handleSubmit() {const _self = this;if (!this.hasSign) {uni.showToast({title: '签名不能为空',icon: 'none',duration: 2000})return;}uni.canvasToTempFilePath({fileType: 'png',quality: 1, //图片质量canvasId: 'myCanvas',success(res) {uni.getImageInfo({// 获取图片的信息src: res.tempFilePath,success: (res1) => {// 将canvas1的内容复制到canvas2中let canvasContext = uni.createCanvasContext('myCanvas2', _self);canvasContext.translate(0, _self.width);canvasContext.rotate((-90 * Math.PI) / 180);canvasContext.drawImage(res.tempFilePath, 0, 0, _self.width, _self.height);canvasContext.draw(false, () => {// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中uni.canvasToTempFilePath({// 把当前画布指定区域的内容导出生成指定大小的图片。在 draw() 回调里调用该方法才能保证图片导出成功。 fileType: 'png',quality: 1, //图片质量canvasId: 'myCanvas2',complete(res2) {//此处是将图片文件传给父级组件上传至后台_self.$emit("submitSignature", res2.tempFilePath);}}, _self)})}})}}, this)},//返回上级handleBack() {this.handleReset();this.$emit("close");},}};
</script><style>page {background: #fbfbfb;height: auto;overflow: hidden;}.wrapper {width: 100%;height: 95vh;margin: 15px 0;overflow: hidden;display: flex;align-content: center;flex-direction: row;justify-content: center;font-size: 28rpx;}.handWriting {background: #fff;width: 100%;height: 95vh;}.handRight {display: inline-flex;align-items: center;width: 45x;}.handCenter {border: 4rpx dashed #e9e9e9;flex: 1;overflow: hidden;box-sizing: border-box;}.handTitle {transform: rotate(90deg);flex: 1;color: #666;line-height: 100%;}.handBtn button {font-size: 28rpx;}.handBtn {height: 95vh;width: 50px;display: inline-flex;flex-direction: column;justify-content: space-between;align-content: space-between;}.delBtn {position: absolute;top: 250rpx;left: 0rpx;transform: rotate(90deg);color: #666;}.subBtn {position: absolute;bottom: 52rpx;left: -3rpx;display: inline-flex;transform: rotate(90deg);background: #008ef6;color: #fff;margin-bottom: 30rpx;text-align: center;justify-content: center;}.saveBtn {position: absolute;top: 375rpx;left: 0rpx;transform: rotate(90deg);color: #666;}
</style>
最后保存的图片是经过旋转后的。