uniapp实现手写签名,并在app中将其转为base64格式的图片

ops/2024/12/22 13:12:33/

这里写自定义目录标题

  • 1 手写签名页面:
  • 2 封装canvas组件:
  • 3 预览base64格式的签名图片:

uniapp实现手写签名,并在app中将其转为base64格式的图片
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1 手写签名页面:

<template>
<!--  手写签名--><!-- <view class="signatrueContent" @tap="startHui"> --><view class="signatrueContent"><view class="title" @tap="cancel">取消</view><!-- <view class="title1" :class="{'isHui':!isShowTrue}" @tap="clearSign"><image src="@/static/image/delectIco.png" alt="" /><view>删除</view></view><view class="title2" @tap="confirmerSignature">确定</view> --><!-- <view v-if="!isShowTrue" class="title3">请在此处手写绘制签名</view> --><view class="signatrueMain" ><!-- <view class="leftSignature" @tap="startHui"> --><view class="leftSignature"><signaturecanvasWidth="96%"canvasHeight="96%"ref="autograph"></signature></view></view></view></template><script>export default {data() {return {showSign: true,isShowTrue: false}},methods: {cancel(){uni.navigateBack()},// startHui(){// 	this.isShowTrue = true// },clearSign() {//  清空this.$refs.autograph.clearArea();},confirmerSignature() {//把base64显示在签名处let src = this.$refs.autograph.checkEmpty();console.log(this.$refs.autograph)console.log("最后===" + src)//旋转图片this.rotateBase64Img(src, -90, this.callback);this.showSign = false;// this.toggle = trueconsole.log('确定');},},created() {},}
</script>
<style scoped lang="less">
.signatrueMain {position: relative;
}@media screen and (orientation: portrait) {/*竖屏 css*/.signatrueContent {// padding: 40rpx 54rpx;// width: 100vw;height: 100vh;position: relative;background: #E8F3FF;.title {color: #111111;font-weight: 600;font-size: 32rpx;-webkit-transform: rotate(90deg);transform: rotate(90deg);-webkit-transform-origin: right center;transform-origin: right center;position: absolute;right: 31px;top: 50px;z-index: 999999;}.title3 {color: #111111;font-size: 32rpx;   -webkit-transform: rotate(90deg);transform: rotate(90deg);-webkit-transform-origin: right center;transform-origin: right center;position: absolute;right: 50%;text-align: center;z-index: 9999;top: 55%;}.title1 {color: #111111;-webkit-transform: rotate(90deg);transform: rotate(90deg);-webkit-transform-origin: right center;transform-origin: right center;position: absolute;left: -33rpx;bottom: 50rpx;display: flex;align-items: center;justify-content: center;width: 158rpx;height: 64rpx;border-radius: 8rpx;background: #1578FF;font-size: 24rpx;color: #fff;z-index: 999;image {margin-right: 2px;width: 24rpx;height: 24rpx;}}.title2 {color: #111111;font-size: 32rpx;-webkit-transform: rotate(90deg);transform: rotate(90deg);-webkit-transform-origin: right center;transform-origin: right center;position: absolute;right: 31px;color: #1578FF;font-weight: 600;z-index: 9999;bottom: 28px;}.signatrueMain {display: -ms-flexbox;height: 100%;width: 100%;}.buttonType {-webkit-transform: rotate(90deg);-moz-transform: rotate(90deg);-ms-transform: rotate(90deg);transform: rotate(90deg);transform-origin: 40% 96%;}.leftSignature {width: 100%;height: 100%;padding: 20rpx;canvas {width: 100%;height: 100%;transform-origin: 0% 0%;}}.firstButton {position: absolute;bottom: 0;right: 20px;text {color: #1578FF;font-size: 32rpx;}}.secondButton {position: absolute;top: 0;right: 0;text {width: 316rpx;height: 128rpx;margin-top: 34rpx;padding-top: 25rpx;line-height: 50rpx;img {width: 48rpx;height: 48rpx;}view {font-size: 32rpx;color: #1578FF;}}}canvas {width: 30%;height: 100%;}}}@media screen and (orientation: landscape) {/*横屏 css*/.signatrueContent {padding: 20rpx 24rpx;background: #E8F3FF;.title {color: #111111;font-size: 18rpx;}.signatrueMain {display: flex;}.leftSignature {width: 100%;height: 100%;margin-right: 25rpx;}.firstButton {button {width: 64rpx;height: 64rpx;background: #EBF3FF;border-radius: 8rpx;img {width: 24rpx;height: 29rpx;}view {font-size: 12rpx;color: #333333;}}}.secondButton {text {margin-top: 34rpx;width: 64rpx;height: 64rpx;background: #3171FF;border-radius: 8rpx;img {width: 24rpx;height: 24rpx;}view {font-size: 12rpx;color: #ffffff;}}}}}.isHui {opacity: 0.5;}
</style>

2 封装canvas组件:

<template><view class="main-content" v-if="isShow" @tap="startHui"><!-- 签字canvas --><block v-if="showCanvas"><canvasclass="mycanvas" id="mycanvas" canvas-id="mycanvas" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"disable-scroll="true"></canvas><!-- 旋转canvas --></block><block class="" v-else><image :src="imgurl" mode="" class="sign-img"></image></block><canvasclass="rotatCanvas"id="rotatCanvas":style="{ 'z-index': -1, width: `${screenWidth}px`, height: `${(screenWidth * screenWidth) / screenHeight}px` }"canvas-id="rotatCanvas"></canvas><view class="title1" :class="{'isHui':!isShowTrue}" @tap="clear"><image src="@/static/image/delectIco.png" alt="" /><view>删除</view></view><view v-if="!isShowTrue" class="title3">请点击此处手写绘制签名</view><view class="title2" @tap="finish">确定</view><view class="mask" v-if="showModal" @tap.stop><view class="kw-modal flex align-items-center justify-content-center"><view class="kw-modal-content"><view class="flex justify-content-end font-size-34 lightgray"><text class="iconfont icon-guanbi" @tap="close"></text></view><view class="flex justify-content-center font-size-38 font-600 kw-modal-title">{{title}}</view><view class="kw-modal-btnbox flex justify-content-between"><view @tap="cancel" class="kw-modal-btn">{{cancelText}}</view><view @tap="confirm" class="kw-modal-btn">{{confirmText}}</view></view></view></view></view><view class="mask" v-if="showToast"><view class="sign-toast flex align-items-center justify-content-center"><view class="toast-box">请先签名</view></view></view></view>
</template>
<script>
export default {data() {return {ctx: '', //绘图图像points: [], //路径点集合isShowTrue: false,screenWidth: '',screenHeight: '',isRotatShow:false,showModal:false,showToast:false,startX:'',startY:'',moveX:'',moveY:'',imgurl:'',showCanvas:true,title:'提示框',cancelText:'取消',confirmText:'确认',base64Img: ''};},props:{isShow:{type:Boolean,default:true}},mounted() {this.createCanvas();uni.getSystemInfo({success: e => {this.screenWidth = e.screenWidth;this.screenHeight = e.screenHeight - 110;console.log(e,'e')}});},methods: {startHui(){this.isShowTrue = true},show() {this.clear();this.isShow = true;},hide() {this.$emit('close',false)this.showCanvas = true},close(){this.showCanvas = truethis.showModal = false},//取消保存cancel(){this.close()//清除画布this.clear()},confirm(){this.rotat(this.base64Img);},save(){this.showCanvas = falseconsole.log(this.moveX,'moveX')console.log(this.moveY,'moveY')// if(!this.moveX&&!this.moveY){this.showToast = truesetTimeout(()=>{this.showToast = falsethis.showCanvas = true},100)// return false// }this.showModal = truethis.title = '确认签字?'},//创建并显示画布createCanvas() {this.showCanvas = true;this.ctx = uni.createCanvasContext('mycanvas', this); //创建绘图对象//设置画笔样式this.ctx.lineWidth = 2;this.ctx.lineCap = 'round';this.ctx.lineJoin = 'round';},//触摸开始,获取到起点touchstart(e) {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(e) {this.moveX = e.changedTouches[0].x;this.moveX = e.changedTouches[0].y;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() {this.points = [];},draw() {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);},//清空画布clear() {this.ctx.clearRect(0, 0, this.screenWidth, this.screenHeight);this.ctx.draw(true);this.moveX = '';this.moveY = '';this.showCanvas = true},//完成绘画并保存到本地finish() {// console.log(this.moveX,this.moveY,11)// if(!this.moveX && !this.moveY){//     uni.showToast({//         title: '请手写签名',//         icon: 'none'//     });//     return// }uni.canvasToTempFilePath({canvasId: 'mycanvas',success: res => {this.imgurl = res.tempFilePath;plus.io.resolveLocalFileSystemURL(res.tempFilePath, entry => {entry.file(file => {const fileReader = new plus.io.FileReader();fileReader.onload = e => {this.base64Img = e.target.result; // 保存 base64 编码的图片this.save();};fileReader.readAsDataURL(file);});});},complete: com => {}},);},// 将图片选装rotat(e) {// this.isRotatShow = true// this.showCanvas = truelet rotatCtx = uni.createCanvasContext('rotatCanvas', this); //创建绘图对象// 重新定位中心点rotatCtx.translate(0, (this.screenWidth * this.screenWidth) / this.screenHeight);// rotatCtx.translate(0, 0);// 将画布逆时针旋转90度rotatCtx.rotate((270 * Math.PI) / 180);// 将签字图片绘制进入CanvasrotatCtx.drawImage(e, 0, 0, (this.screenWidth * this.screenWidth) / this.screenHeight, this.screenWidth);// 保存后旋转后的结果rotatCtx.draw(true);setTimeout(() => {// 生成图片并回调uni.canvasToTempFilePath({canvasId: 'rotatCanvas',success: res => {plus.io.resolveLocalFileSystemURL(res.tempFilePath, entry => {entry.file(file => {const fileReader = new plus.io.FileReader();fileReader.onload = e => {console.log('tempFilePath', e.target.result)this.showCanvas = falseuni.setStorageSync('handleImgUrl',e.target.result)console.log(e.target.result,'绘制的')setTimeout(() => {this.hide();uni.navigateBack({delta: 1});}, 100);};fileReader.readAsDataURL(file);});});},complete: com => {// console.log(com);}},this);}, 500);}}
};
</script>
<style lang="scss" scoped>
.title3 {color: #111111;font-size: 32rpx;   -webkit-transform: rotate(90deg);transform: rotate(90deg);-webkit-transform-origin: right center;transform-origin: right center;position: absolute;right: 50%;text-align: center;z-index: 9999;top: 55%;}
.title1 {color: #111111;-webkit-transform: rotate(90deg);transform: rotate(90deg);-webkit-transform-origin: right center;transform-origin: right center;position: absolute;left: -33rpx;bottom: 50rpx;display: flex;align-items: center;justify-content: center;width: 158rpx;height: 64rpx;border-radius: 8rpx;background: #1578FF;font-size: 24rpx;color: #fff;z-index: 999;image {margin-right: 2px;width: 24rpx;height: 24rpx;}}.title2 {color: #111111;font-size: 32rpx;-webkit-transform: rotate(90deg);transform: rotate(90deg);-webkit-transform-origin: right center;transform-origin: right center;position: absolute;right: 31px;color: #1578FF;font-weight: 600;z-index: 999;bottom: 28px;}
.main-content {width: 100vw;height: 100vh;z-index: 9999;overflow: hidden;max-height:100vh;
}
.mycanvas {width: 100vw;height: 100%;background-color: #E8F3FF;position: fixed;left: 0rpx;top: 0rpx;z-index: 2;
}
.sign-img{width: 100vw;height: 100vh;
}
.rotatCanvas{background-color: red;
}
.button-line {transform: rotate(90deg);position: fixed;bottom: -130rpx;left: 260rpx;align-items: center;justify-content: space-between;z-index: 999;
}
.button-style {color: #ffffff;width: 100px;height: 120rpx;text-align: center;line-height: 120rpx;border-radius: 10rpx;margin-bottom: 40rpx;font-size: 34rpx
}
.save-button {@extend .button-style;background-color: #02b340;height: 140rpx;line-height: 140rpx;
}
.clear-button {@extend .button-style;background-color: #ffa500;height: 140rpx;line-height: 140rpx;
}
.cancel-button {@extend .button-style;background-color: #e10b2b;
}.mask{width: 100vw;height: 100vh;background: rgba(0,0,0,0.8) ;position: absolute;top: 0;left: 0;z-index: 999;}.kw-modal,.sign-toast{width: 50vw;height: calc(100vh - 210px);transform: rotate(90deg);position: absolute;top: 0;left: -65rpx;text-align: center;z-index: 999;}.kw-modal-content{width: 690rpx;// height: 400rpx;background: #efefef;border-radius: 30rpx;padding: 38rpx 30rpx 70rpx;.kw-modal-title{margin-top: 22rpx;}.kw-modal-tips{margin-top: 20rpx;}.kw-modal-inp{margin-top: 50rpx;.kw-inp{border: 1rpx solid #D9D9D9;border-radius: 4rpx;height: 70rpx;line-height: 70rpx;padding: 0 30rpx;}.inp-title{margin-right: 20rpx;}}.kw-modal-btnbox{margin-top: 100rpx;display: flex;justify-content: space-around;.kw-modal-btn{width: 300rpx;height: 84rpx;background: #D9D9D9;border-radius: 60rpx;line-height: 84rpx;text-align: center;font-size: 30rpx;&:last-child{color: #FFFFFF;background: #59A3FF;}}}}.toast-box{padding: 15rpx 30rpx;// background-color: rgba(0, 0, 0, .7);// color: #fff;background-color: #ffffff;color: #ffa500;border-radius: 8rpx;font-size: 30rpx;}
</style>

3 预览base64格式的签名图片:

<view class="yzView"><view class="yztext">印章预览</view><view class="isYzBox"><image class="yzimg" mode="heightFix" :src="handleImg" alt=""></view>
</view>onShow(){this.getSignet()if(uni.getStorageSync('handleImgUrl')){this.handleImg = uni.getStorageSync('handleImgUrl')console.log(this.handleImg,'canvas') }
}

http://www.ppmy.cn/ops/144025.html

相关文章

基于 iAP2 协议 的指令协议,用于对安防设备的 MCU 进行操作

协议设计目标 1. 安全性&#xff1a;通过 iAP2 协议与 MCU 设备进行安全通信。 2. 通用性&#xff1a;支持对安防设备的常见功能进行操作&#xff0c;如状态查询、设备控制、参数配置等。 3. 高效性&#xff1a;数据结构简洁清晰&#xff0c;易于解析和扩展。 4. 扩展性&#x…

jenkins 出现 Jenkins: 403 No valid crumb was included in the request

文章目录 前言解决方式:1.跨站请求为找保护勾选"代理兼容"2.全局变量或者节点上添加环境变量3.&#xff08;可选&#xff09;下载插件 the strict Crumb Issuer plugin4.重启 前言 jenkins运行时间长了&#xff0c;经常出现点了好几次才能构建&#xff0c;然后报了Je…

【python】OpenCV—Image Moments

文章目录 1、功能描述2、图像矩3、代码实现4、效果展示5、完整代码6、涉及到的库函数cv2.moments 7、参考 1、功能描述 计算图像的矩&#xff0c;以质心为例 2、图像矩 什么叫图像的矩&#xff0c;在数字图像处理中有什么作用&#xff1f; - 谢博琛的回答 - 知乎 https://ww…

大模型技术优化负载均衡:AI驱动的智能化运维

在现代信息技术环境中&#xff0c;负载均衡是确保系统稳定、高效运行的关键技术。随着大模型技术&#xff08;Large Model Technology, LMT&#xff09;的发展&#xff0c;AI驱动的智能化负载均衡成为了优化系统性能、提升用户体验的重要手段。本文将详细介绍如何使用Python实现…

linux springboot项目启动端口被占用 Port 8901 was already in use.

....eb server failed to start. Port 8901 was already in use.Action:Identify and stop the process thats listening on port 8901 or configure this application to listen on another port.问题分析 这个错误表明端口 8901 已被其他进程占用。为了启动你的应用&#xf…

基于Spring Boot的新能源汽车个性化推荐系统

一、系统背景与意义 随着新能源汽车市场的快速发展&#xff0c;消费者对新能源汽车的需求日益多样化。为了满足消费者的个性化需求&#xff0c;提高购车体验&#xff0c;开发一个基于Spring Boot的新能源汽车个性化推荐系统显得尤为重要。该系统能够根据用户的偏好、历史行为等…

【单片机原理】第1章 微机基础知识,运算器,控制器,寄存器,微机工作过程,数制转换

关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…

Java模拟多个Mqtt客户端连接Mqtt Broker

上一次我们介绍了Java模拟单个Mqtt客户端的场景&#xff0c;但是在实际的业务场景中&#xff0c;可能需要我们模拟多个Mqtt客户端&#xff0c;比如&#xff1a;我们要对云平台的连接和设备上下行做压测。 Java模拟多个Mqtt客户端基本流程 引入Paho MQTT客户端库 <depende…