uniapp实现手写签字功能
首先,在components下新建 signView.vue文件
<template> <view class="main-content" v-if="isShow"> <!-- 签字canvas --> <block v-if="showCanvas"> <canvas class="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> <canvas class="rotatCanvas" id="rotatCanvas" :style="{ 'z-index': -1, width: `${screenWidth}px`, height: `${(screenWidth * screenWidth) / screenHeight}px` }" canvas-id="rotatCanvas" ></canvas> <view class="button-line"> <view class="save-button" @tap.stop="finish">保存</view> <view class="clear-button" @tap.stop="clear">清除</view> <view class="cancel-button" @tap.stop="hide">关闭</view> </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: [], //路径点集合 screenWidth: '', screenHeight: '', isRotatShow:false, showModal:false, showToast:false, startX:'', startY:'', moveX:'', moveY:'', imgurl:'', showCanvas:true, title:'提示框', cancelText:'取消', confirmText:'确认', }; }, 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: { show() { this.clear(); this.isShow = true; }, hide() { this.$emit('close',false) this.showCanvas = true }, close(){ this.showCanvas = true this.showModal = false }, //取消保存 cancel(){ this.close() //清除画布 this.clear() }, confirm(){ this.rotat(this.imgurl); }, save(){ this.showCanvas = false console.log(this.moveX,'moveX') console.log(this.moveY,'moveY') if(!this.moveX&&!this.moveY){ this.showToast = true setTimeout(()=>{ this.showToast = false this.showCanvas = true },1500) return false } this.showModal = true this.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() { uni.canvasToTempFilePath( { canvasId: 'mycanvas', success: res => { this.imgurl = res.tempFilePath this.save() }, complete: com => {} }, this ); }, // 将图片选装 rotat(e) { // this.isRotatShow = true // this.showCanvas = true let 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); // 将签字图片绘制进入Canvas rotatCtx.drawImage(e, 0, 0, (this.screenWidth * this.screenWidth) / this.screenHeight, this.screenWidth); // 保存后旋转后的结果 rotatCtx.draw(true); setTimeout(() => { // 生成图片并回调 uni.canvasToTempFilePath( { canvasId: 'rotatCanvas', success: val => { console.log('tempFilePath', val.tempFilePath) this.showCanvas = false this.$emit('savesign', {tempFilePath: val.tempFilePath ,flag: true} ); setTimeout(() => { this.hide(); }, 500); }, complete: com => { // console.log(com); } }, this ); }, 500); } } }; </script> <style lang="scss" scoped> .main-content { width: 100vw; height: 100vh; background-color: #ffffff; z-index: 9999; overflow: hidden; max-height:100vh; } .mycanvas { width: 100vw; height: calc(100vh - 120px); background-color: #efefef; position: fixed; left: 0rpx; top: 0rpx; z-index: 2; } .sign-img{ width: 100vw; height: calc(100vh - 110px); } .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: 0; 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>
在需要用到的页面引入
import SignView from '@/pages/user/components/signView.vue'
components:{ SignView },
<view class="c-form-item"> <text class="c-form-labels"> <text class="cuIcon-peoplefill c-m-r-10"></text> <text style="color: red;vertical-align: sub;margin-right: 10rpx;">*</text><text>技术工程师签字</text> </text> </view> <view class="tech-sign" @click="changeIsShow" v-if="!imgFlag"> <van-icon name="orders-o" size="20" color="#ccc"/> <view class="down-sign"> 点击横屏进行签字 </view> </view> <view class="canvasbox" v-else> <image class="canvas-img" :src="imgUrl" mode=""></image> </view> <sign-view v-if="isShow" @close="close" @savesign="savesign"></sign-view>
data(){ return { isShow: false, imgFlag: false, imgUrl:'' } }, methods:{ changeIsShow(){ this.isShow = true }, close(value){ this.isShow = value }, savesign(data){ this.imgUrl = data.tempFilePath this.imgFlag = data.flag }, }