uniapp uses canvas to implement the signature function (compatible with h5, app, and small programs)

uniapp uses canvas to implement the signature function (compatible with h5, app, and small programs)


Preface

A set of codes achieves compatibility. The main difference is how to convert the image address to base64 and give it to the backend after getting it.


提示:以下是本篇文章正文内容,下面案例可供参考

html
<template>
	<view class="signa">
		<view class="btn">
			<view class="hand-title">手写签名</view>
			<view @click="clear" class="rewrite-btn">重写</view>
			<view @click="save" class="save-btn">使用</view>
		</view>
		<view class="canvas-wrap">
			<canvas class="canvas" disable-scroll="true" canvas-id="canvasId" @touchstart="starts" @touchmove="moves" @touchend="end"></canvas>
		</view>
		<Message ref="Message"></Message>
	</view>
</template>
css

Adjust the style and html according to your own needs, the main code is in js

<style scoped lang="scss">
	.signa {
    
    
		position: relative;
		overflow: hidden;
		height: 100vh;
		width: 100vw;
		z-index: 1;
		.canvas-wrap {
    
    
			display: flex;
			justify-content: center;
			align-items: center;
			width: calc(100vw - 180rpx);
			height: 100vh;
		}
		.canvas {
    
    
			width: 100%;
			height: 100vh;
			background-color: #f4f8fb;
			position: absolute;
			z-index: 9999;
		}
		.btn {
    
    
			width: 160rpx;
			right: 0;
			position: fixed;
			font-size: 40rpx;
			.cancel-btn {
    
    
				position: fixed;
				top: 30rpx;
				right: 0;
				color: $uni-text-color-blue;
				transform: rotate(90deg);
			}
			.hand-title {
    
    
				position: fixed;
				top: 45%;
				right: -40rpx;
				transform: rotate(90deg);
			}
			.rewrite-btn {
    
    
				position: fixed;
				top: 80%;
				right: 0;
				color: #666666;
				font-size: 36rpx;
				transform: rotate(90deg);
			}
			.save-btn {
    
    
				position: fixed;
				bottom: 60rpx;
				right: -10rpx;
				padding: 0 10rpx;
				color: #fff;
				background: #f43e3c;
				border-radius: 7rpx;
				transform: rotate(90deg);
				font-size: 36rpx;
			}
		}
	}
</style>
js

Use // #ifdef MP-WEIXIN || APP-PLUS|| H5 // #endif to realize which end you are currently on and which method to take

<script>
	/*
	 *	已兼容h5,小程序端,app端 
	 */
	import boboMessage from "@/landlord/signContract/components/bobo-message/bobo-message.vue";
	export default {
    
    
		data() {
    
    
			return {
    
    
				dom: null,
				line: [],
				radius: 0,
				isMove: false,
				main: {
    
    },
				pdfURl: '',
				showCanvas: false,
				ctx: '', //绘图图像
				points: [], //路径点集合 
				signature: '',
				content: '',
				base64: '',
				sureForm: {
    
    } //上一页带过来的数据
			};
		},
		components: {
    
    
			Message: boboMessage,
		},
		created() {
    
    
			this.dom = uni.createCanvasContext("canvasId", this);
		},
		onLoad: function(options) {
    
    
			//接收上一页的数据
			let item = JSON.parse(options.tranform)
			this.sureForm = item
		},
		methods: {
    
    
			end(e) {
    
    },
			distance(a, b) {
    
    
				let x = b.x - a.x;
				let y = b.y - a.y;
				return Math.sqrt(x * x + y * y);
			},
			starts(e) {
    
    
				this.line.push({
    
    
					points: [{
    
    
						time: new Date().getTime(),
						x: e.touches[0].x,
						y: e.touches[0].y,
						dis: 0,
					}, ],
				});
				let currentPoint = {
    
    
					x: e.touches[0].x,
					y: e.touches[0].y,
				};
				this.currentPoint = currentPoint;
				this.drawer(this.line[this.line.length - 1]);
			},
			moves(e) {
    
    
				this.isMove = true;
				let point = {
    
    
					x: e.touches[0].x,
					y: e.touches[0].y,
				};
				(this.lastPoint = this.currentPoint), (this.currentPoint = point);
				this.line[this.line.length - 1].points.push({
    
    
					time: new Date().getTime(),
					x: e.touches[0].x,
					y: e.touches[0].y,
					dis: this.distance(this.currentPoint, this.lastPoint),
				});
				this.drawer(this.line[this.line.length - 1]);
			},
			drawer(item) {
    
    
				let x1,
					x2,
					y1,
					y2,
					len,
					radius,
					r,
					cx,
					cy,
					t = 0.5,
					x,
					y;
				var time = 0;
				if (item.points.length > 2) {
    
    
					let lines = item.points[item.points.length - 3];
					let line = item.points[item.points.length - 2];
					let end = item.points[item.points.length - 1];
					x = line.x;
					y = line.y;
					x1 = lines.x;
					y1 = lines.y;
					x2 = end.x;
					y2 = end.y;
					var dis = 0;
					time = line.time - lines.time + (end.time - line.time);
					dis = line.dis + lines.dis + end.dis;
					var dom = this.dom;
					var or = Math.min(
						(time / dis) * this.linePressure + this.lineMin,
						this.lineMax
					);
					cx =
						(x - Math.pow(1 - t, 2) * x1 - Math.pow(t, 2) * x2) /
						(2 * t * (1 - t));
					cy =
						(y - Math.pow(1 - t, 2) * y1 - Math.pow(t, 2) * y2) /
						(2 * t * (1 - t));
					dom.setLineCap("round");
					dom.beginPath();
					dom.setStrokeStyle("black");
					dom.setLineWidth(5);
					dom.moveTo(x1, y1);
					dom.quadraticCurveTo(cx, cy, x2, y2);

					dom.stroke();
					dom.draw(true);
				}
			},
			clear() {
    
    
				this.dom.clearRect(0, 0, 1000, 1000);
				this.dom.draw();
				this.isMove = false;
			},
			
			// 以上方法可拿去直接用,接下来是重点
			
			save() {
    
    
				uni.showLoading({
    
    
					title: "加载中",
					mask: true
				});
				if (!this.isMove) return this.$refs.Message.error("尚未进行签名!");
				// 小程序拿到图片转base64方法
				// #ifdef MP-WEIXIN
				uni.canvasToTempFilePath({
    
    
					canvasId: "canvasId",
					fileType: 'png',
					quality: 1, //图片质量
					success: (res) => {
    
    
						var baseAddress;
						uni.getFileSystemManager().readFile({
    
    
							filePath: res.tempFilePath, //选择图片返回的相对路径
							encoding: 'base64', //编码格式
							success: res => {
    
    
								// 成功的回调
								this.baseAddress = 'data:image/jpeg;base64,' + res.data
								// ... 后端接口的地方
							}
						})
					}
				});
				// #endif
				// h5的方法
				// #ifdef H5
				uni.canvasToTempFilePath({
    
    
					canvasId: "canvasId",
					fileType: 'png',
					quality: 1, //图片质量
					success: (res) => {
    
    
						var baseAddress;
						uni.request({
    
    
							url: res.tempFilePath,
							method:'GET',
							responseType:'arraybuffer',
							success: ress => {
    
    
								// 成功的回调
								this.baseAddress = 'data:image/jpeg;base64,' + uni.arrayBufferToBase64(ress.data)
								// ... 后端接口的地方
							}
						})
						
					}
				});
				// #endif
				// app的方法
				// #ifdef APP-PLUS
				uni.canvasToTempFilePath({
    
    
					canvasId: 'canvasId',
					success: function(res) {
    
    
						var path = res.tempFilePath;
						var base64;
						return new Promise((resolve, reject) => {
    
    
							plus.io.resolveLocalFileSystemURL(path, function(entry) {
    
    
								entry.file(function(file) {
    
    
									var AppReader = new plus.io.FileReader();
									AppReader.onloadend = function(e) {
    
    
										that.base64 = e.target.result
										// 拿到bade64调接口
										that.saveForm(that.base64)
										resolve(base64.split(",")[1])
									};
									AppReader.onerror = function(err) {
    
    
										reject(err)
									};
									AppReader.readAsDataURL(file);
								}, function(e) {
    
    
									reject(e)

								});
						 });
						})
					}
				})
				// #endif
			},
			// #ifdef APP-PLUS
			saveForm(val) {
    
    
				let params = {
    
    
					
				}
				*****(params).then(req => {
    
    
					if (req.data.code == 0) {
    
    
						this.$u.toast(req.data.message)
						uni.navigateBack({
    
    
							delta:2
						})
					} else {
    
    
						this.$u.toast(res.data.message);
					}
				})
			}
			// #endif
		}
	};
</script>

效果如下:
Insert image description here

Guess you like

Origin blog.csdn.net/m0_56144469/article/details/128232052