uniapp 小程序 实现 vue 实现手写签名
方法一
<template> <view class="signBox"> <view class="topHint">请在下方空白书写区域内写出您的名字</view> <view class="btn"> <view class="saveBtn" @click="save">确认</view> <view class="cancelBtn" @click="clear">清除</view> </view> <canvas class="canvas" disable-scroll="true" :style="{'width':width,'height':height}" canvas-id="designature" @touchstart="starts" @touchmove="moves" @touchend="end"></canvas> </view> </template> <script> export default { components: {}, data() { return { dom: null, line: [], radius: 0, width: '0rpx', height: '0rpx', } }, onLoad() {}, computed: {}, created() { uni.getSystemInfo({ success: (res) => { this.width = res.windowWidth - 60 + 'rpx'; this.height = res.windowHeight - 56 + 'rpx'; } }); this.dom = uni.createCanvasContext('designature', this); }, onShow() {}, 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) { 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() }, // 保存图片 save() { var t = this; uni.canvasToTempFilePath({ canvasId: 'designature', fileType: 'png', quality: 1, //图片质量 success: function(res) { t.$emit('getImg', res.tempFilePath) console.log(res.tempFilePath, '148') // uni.navigateBack({ // delta:1 // }) }, fail(e) { console.log(e) } }, this) } } } </script> <style scoped lang="less"> .signBox { position: relative; overflow: hidden; background-color: #F6F6F6; height: 100vh; width: 100vw; .canvas { width: 100% !important; background-color: #FFFFFF; position: absolute; z-index: 9999; left: 0rpx; top: 25rpx; // border: 1rpx solid #d6d6d6; } .topHint{ width: 100%; height: 25rpx; line-height: 25rpx; font-size: 15rpx; color: #999999; text-align: center; background: ; } .btn { width: 100%; height: 60rpx; position: fixed; bottom: 0; // background-color: red; display: flex; align-items: center; justify-content: center; .saveBtn { width: 190rpx; height: 40rpx; line-height: 40rpx; background: linear-gradient(306deg, #4281EA 0%, #6363F2 100%); border-radius: 10rpx; text-align: center; font-size: 18rpx; color: #FFFFFF; margin-right: 10rpx; } .cancelBtn { width: 190rpx; height: 40rpx; line-height: 40rpx; background: #FFFFFF; border-radius: 10rpx; text-align: center; font-size: 18rpx; color: #222222; margin-left: 10rpx; } } } </style> json文件 { "path": "pages/clientDitch/sign", "style": { "navigationBarTitleText": "签字手签", "pageOrientation": "landscape", //控制横屏 // "navigationStyle": "custom" } },
方法二
<template> <view class="signBox column-me"> <!-- 这个是自定义的title-可根据自己封装的title的作为调整 --> <status-bar title="电子签名" :bgColor="null"></status-bar> <view class="topHint">请绘制清晰可辨的签名并保存</view> <canvas class="canvas flex1" :canvas-id="cid" :id="cid" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend" :disable-scroll="true"></canvas> <view class="btn margin-top10 margin-bottom10"> <view class="cancelBtn" @click="reWrite">重写</view> <view class="saveBtn margin-left30" @click="save">保存</view> </view> </view> </template> <script> export default { components: {}, data() { return { line: [], radius: 0, taskId: '', //以下与签名有关参数 dom: null, cid: 'canvas', //画布id Strokes: [], showCanvasDialog: false, canvasImg: '', //签名图片 } }, onLoad(e) { this.taskId = e.taskId }, computed: {}, mounted: function() { let that = this this.initCanvas() }, methods: { initCanvas() { let that = this this.$nextTick(function() { this.dom = uni.createCanvasContext(this.cid, this); var query = wx.createSelectorQuery(); query.select('#canvas').boundingClientRect(); query.exec(function(res) { let widths = res[0].width let heights = res[0].height that.dom.rect(0, 0, widths, heights) that.dom.setFillStyle('#FFFFFF') that.dom.fill() that.dom.draw() }) }); }, touchstart(e) { this.Strokes.push({ imageData: null, style: { color: '#000000', lineWidth: '3', }, points: [{ x: e.touches[0].x, y: e.touches[0].y, type: e.type, }] }) this.drawLine(this.Strokes[this.Strokes.length - 1], e.type); }, touchmove(e) { this.Strokes[this.Strokes.length - 1].points.push({ x: e.touches[0].x, y: e.touches[0].y, type: e.type, }) this.drawLine(this.Strokes[this.Strokes.length - 1], e.type); }, touchend(e) { if (this.Strokes[this.Strokes.length - 1].points.length < 2) { //当此路径只有一个点的时候 this.Strokes.pop(); } }, drawLine(StrokesItem, type) { if (StrokesItem.points.length > 1) { this.dom.setLineCap('round') this.dom.setStrokeStyle(StrokesItem.style.color); this.dom.setLineWidth(StrokesItem.style.lineWidth); this.dom.moveTo(StrokesItem.points[StrokesItem.points.length - 2].x, StrokesItem.points[StrokesItem .points.length - 2].y); this.dom.lineTo(StrokesItem.points[StrokesItem.points.length - 1].x, StrokesItem.points[StrokesItem .points.length - 1].y); this.dom.stroke(); this.dom.draw(true); } }, //重写签名 reWrite() { this.Strokes = []; this.dom.draw(); this.initCanvas() }, // 保存图片 save() { let that = this uni.canvasToTempFilePath({ canvasId: 'canvas', fileType: 'png', quality: 1, //图片质量 success: function(res) { let imgs = [res.tempFilePath] that.$.upload_img(imgs, 0, res => { let imgUrl = res.data //签名图片 let mediaUrl = that.$.get_data('mediaUrl') //采集图片 if (that.$.isEmpty(mediaUrl)) { mediaUrl = '' } that.$.ajax("POST", "/customer/user/checkTask", { taskId: that.taskId, status: 1, //状态:1同意2拒绝 signImage: imgUrl, userVideo: mediaUrl, }, (res) => { if (res.code === 1000) { that.$.ti_shi(res.message) setTimeout(() => { uni.$emit('signOk') that.$.back() }, 1000) } else { that.$.ti_shi(res.message) } }); }) }, fail(e) { console.log(e) } }) } } } </script> <style scoped lang="less"> .signBox { position: relative; overflow: hidden; background-color: #F6F6F6; height: 100vh; width: 100vw; .canvas { width: 100%; background: #FFFFFF; } .topHint { width: 100%; height: 60rpx; line-height: 60rpx; font-size: 28rpx; color: #6D7984; text-align: center; background: ; } .btn { width: 100%; height: 132rpx; display: flex; align-items: center; justify-content: center; .saveBtn { width: 300rpx; height: 88rpx; line-height: 88rpx; background: #215AA0; border-radius: 20rpx; text-align: center; font-size: 32rpx; color: #FFFFFF; } .cancelBtn { width: 298rpx; height: 86rpx; line-height: 86rpx; background: #FFFFFF; border-radius: 20rpx; text-align: center; font-size: 32rpx; color: #202233; border: 1px solid #BBC4CC; } } } </style>