来源:
公司的一个需求,需要给新注册的会员和客商需要增加签署协议功能;
之前的思路:
1、使用vue-signature-pad来实现电子签名,但是安卓手机不兼容;
2、uniapp插件市场来实现,但是对HBuilderX的版本有要求,无奈公司只能使用3.4.7版本;
前面2种思路都不行那就用Canvas来实现
Canvass
canvas 是 html 的一个标签,它可以结合 JavaScript 提供的 canvasApi 来绘制各种各样的图形。canvas 主要用于绘制 2D 图形。注意:当你不设置 canvas 的宽高时,它的默认宽高是 300px、150px。
需要实现的功能如图:
代码实现
EctronicSignature.vue<template><view class="ectronic-signature"><canvasclass="board-canvas"canvas-id="drawCanvas"disable-scroll="true"@touchstart="touchStart"@touchmove="touchMove"@touchend="touchEnd"></canvas><view class="btn"><u-button type="success" @click="saveImage" text="保存" class="btnItem"></u-button><u-button @click="clearDrawBoard" text="清空" class="btnItem"></u-button></view></view>
</template><style lang="scss" scoped>
……
</style>
EctronicSignature.tscurDrawArr: any = [];startX: any = 0;startY: any = 0;ctx: any = {};begin: Boolean = false;bgColor: String = 'white'; //背景色lineWidth: Number = 4; //画笔宽度penMode: Boolean = true; //打开画笔 开关currentTab: any = 1;currentIndex: any = 0;selectPointer: any = []; //所有选中的线cache: any = '';points: any = [];onReady() {this.ctx = uni.createCanvasContext('drawCanvas', this); // 获取canvas上下文对象 vue的写法是先获取,之后通过.getContext("2d")来获取上下文this.cache = new Map(); // 缓存this.ctx.setLineWidth(this.lineWidth); // 设置画笔的粗细}// ctx.draw()绘制结果呈现在canvas// isReverse: 是否保留之前的像素draw(isReverse = false, cb) {this.ctx.draw(isReverse, () => {if (cb && typeof cb == 'function') {cb();}});}// 绘画 开始touchStart(e) {console.log('绘画开始', e.touches[0].x, e.touches[0].y);// customPrint('我能够进行绘制');if (this.penMode) {this.lineBegin(e.touches[0].x, e.touches[0].y);this.lineAddPoint(e.touches[0].x, e.touches[0].y);this.draw(true, ''); // 呈现画面}this.points.push([e.touches[0].x, e.touches[0].y]); // 存储绘制的点this.selectPointer.push([[e.touches[0].x, e.touches[0].y]]);}// 开始绘制线条lineBegin(x, y) {this.begin = true; // 作为一个标记代表开始绘画this.ctx.beginPath(); // 开始创建一个路径this.startX = x;this.startY = y;this.ctx.moveTo(this.startX, this.startY); // 将路径移动到画布中的指定点this.lineAddPoint(x, y); // 绘制线条中间添加}// 绘画 移动touchMove(e) {console.log('绘画移动', e.touches[0].x, e.touches[0].y);if (this.begin) {if (this.penMode) {this.lineAddPoint(e.touches[0].x, e.touches[0].y);this.draw(true, '');}this.points.push([e.touches[0].x, e.touches[0].y]);this.selectPointer[this.selectPointer.length - 1].push([e.touches[0].x, e.touches[0].y]);}}// 绘制线条中间添加点lineAddPoint(x, y) {this.ctx.moveTo(this.startX, this.startY);this.ctx.lineTo(x, y); // 增加一个新的点,然后创建一条从上次指定点到目标点的线this.ctx.stroke(); // 画出当前路径的边框this.startX = x;this.startY = y;}// 绘画 结束touchEnd(e) {if (this.penMode) {// this.curDrawArr = [];this.points = [];this.lineEnd();}}// 绘制线条结束lineEnd() {this.ctx.closePath(); // 关闭一个路径,关闭路径会连接起点和终点this.begin = false;}// 检验画布是否为空isCanvasBlank(canvas) {const blank = document.createElement('canvas'); //系统获取一个空canvas对象blank.width = canvas.width;blank.height = canvas.height;return canvas.toDataURL() == blank.toDataURL(); // .toDataURL()将canvas对象转换为base64位编码}// 保存 图片数据saveImage() {const _this = this;uni.canvasToTempFilePath({canvasId: 'drawCanvas',success: function(res) {console.log('res ==>', res);// 在H5平台下,tempFilePath 为 base64// this.uploadimage(res.tempFilePath,"save",page.currentTab)const canvas = document.getElementsByTagName('canvas')[0];if (_this.isCanvasBlank(canvas)) {uni.showToast({title: '请签字!!!',icon: 'none',});return false;}},});}//清除clearDrawBoard() {this.ctx.draw();this.selectPointer = [];}}
推荐资料
https://www.runoob.com/html/html5-canvas.html
https://uniapp.dcloud.net.cn/component/canvas.html#canvas
https://open.dingtalk.com/document/personalapp/setlinewidth