html手写板
js版本
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <div class="sign-page"> <div class="canvas-box"> <div class="canvas" ontouchstart="methods.canvasTouchEvent(event,'canvasStart')" ontouchmove="methods.canvasTouchEvent(event,'canvasMove')" ontouchend="methods.canvasTouchEvent(event,'canvasEnd')"> <div class="title">请在该区域内工整书写您的签名</div> </div> </div> <p class="clearCanvas" onclick="methods.saveOrClear('clear')">清 除</p> <p class="saveCanvas" onclick="methods.saveOrClear('save')">保 存</p> </div> </div> <script> const temp = { canvas: null, // 画布el对象 cxt: null, // 上下文 stageInfo: null, // 返回canvas的大小及位置 isSign: false //未签名提示 } const data = new Proxy(temp, { set(target, property, value, receiver) { if (property === 'isSign') { console.log(value); document.querySelector('.title').style.display = value ? 'none' : 'block' } return Reflect.set(target, property, value); }, get(target, key) { return Reflect.get(target, key); }, }) const methods = { /* * 画布初始化事件 */ initCanvas(obj) { data.canvas = document.createElement('canvas'); // 指定canvas obj.el.appendChild(data.canvas); data.cxt = data.canvas.getContext('2d'); // 设置2D渲染区域 data.canvas.width = obj.el.clientWidth; data.canvas.height = obj.el.clientHeight; data.cxt.fillStyle = '#ffffff'; data.cxt.strokeStyle = '#000000'; data.cxt.fillRect(0, 0, data.canvas.width, data.canvas.width); data.cxt.lineWidth = 2; // 设置线的宽度 data.cxt.lineCap = 'round'; data.stageInfo = data.canvas.getBoundingClientRect(); }, /* * 画布touch相关事件处理 */ canvasTouchEvent(e, type) { const cxt = data.cxt; const postion = [e.changedTouches[0].pageX - data.stageInfo.left, e.changedTouches[0].pageY - data.stageInfo.top] const handle = { canvasStart: () => { cxt.beginPath(); cxt.moveTo(...postion); }, canvasMove: () => { if (!e && !e.preventDefault) return; e.preventDefault(); cxt.lineTo(...postion); cxt.stroke(); data.isSign = true; }, canvasEnd: () => cxt.closePath } handle[type](); }, /* * 清除和保存事件 */ saveOrClear(type) { if (type === 'clear') { data.cxt.clearRect(0, 0, data.canvas.width, data.canvas.height); data.isSign = false; return false; } if (data.isSign) { const imgBase64 = data.canvas.toDataURL(); console.log(imgBase64); } else { data.$dialog.alert({ title: '错误', message: '请绘制签名', messageAlign: 'center' }); } } } const p = new Proxy(data, { set(target, property, value, receiver) { console.log(key); if (property === 'isSign') { console.log('isSign'); } return Reflect.set(target, key, value); } }) setTimeout(() => { methods.initCanvas({ el: document.querySelector('.canvas') }); }) </script> <style> .canvas-box { width: calc(100% - 68px); height: calc(100% - 180px); margin-bottom: 38px; position: relative; border-radius: 6px; background: #fff; padding: 34px; } .canvas { background: #fff; height: 100%; width: 100%; border: 1px dashed #848588; position: relative; border-radius: 6px; } .saveCanvas, .clearCanvas { padding: 10px 0; background: rgba(207, 225, 245, 1); width: 45%; text-align: center; float: left; color: #3F8EE8; } .saveCanvas { margin-left: 10%; } .sign-page { background: #EDF1F6; width: calc(100% - 60px); height: calc(100% - 96px); padding: 58px 30px 38px; position: fixed; top: 0; left: 0; } .title { text-orientation: mixed; font-size: 18px; color: #A0ACBF; position: absolute; padding: 10%; top: 0; left: 0; } </style> </body> </html>
vue版
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <div class="sign-page"> <div class="canvas-box"> <div class="canvas" ref="canvas" @touchstart="canvasTouchEvent($event,'canvasStart')" @touchmove="canvasTouchEvent($event,'canvasMove')" @touchend="canvasTouchEvent($event,'canvasEnd')"> <div class="title" v-if="!isSign">请在该区域内工整书写您的签名</div> </div> </div> <p class="clearCanvas" @click="saveOrClear('clear')">清 除</p> <p class="saveCanvas" @click="saveOrClear('save')">保 存</p> </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { canvas: null, // 画布el对象 cxt: null, // 上下文 stageInfo: null, // 返回canvas的大小及位置 isSign: false //未签名提示 }, methods: { /* * 画布初始化事件 */ initCanvas(obj) { this.canvas = document.createElement('canvas'); // 指定canvas obj.el.appendChild(this.canvas); this.cxt = this.canvas.getContext('2d'); // 设置2D渲染区域 this.canvas.width = obj.el.clientWidth; this.canvas.height = obj.el.clientHeight; this.cxt.fillStyle = '#ffffff'; this.cxt.strokeStyle = '#000000'; this.cxt.fillRect(0, 0, this.canvas.width, this.canvas.width); this.cxt.lineWidth = 2; // 设置线的宽度 this.cxt.lineCap = 'round'; this.stageInfo = this.canvas.getBoundingClientRect(); }, /* * 画布touch相关事件处理 */ canvasTouchEvent(e, type) { const cxt = this.cxt; const postion = [e.changedTouches[0].pageX - this.stageInfo.left, e.changedTouches[0].pageY - this.stageInfo.top] const handle = { canvasStart: () => { cxt.beginPath(); cxt.moveTo(...postion); }, canvasMove: () => { if (!e && !e.preventDefault) return; e.preventDefault(); cxt.lineTo(...postion); cxt.stroke(); this.isSign = true; }, canvasEnd: () => cxt.closePath } handle[type](); }, /* * 清除和保存事件 */ saveOrClear(type) { if (type === 'clear') { this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height); this.isSign = false; return false; } if (this.isSign) { const imgBase64 = this.canvas.toDataURL(); console.log(imgBase64); } else { this.$dialog.alert({ title: '错误', message: '请绘制签名', messageAlign: 'center' }); } } }, mounted() { setTimeout(() => { this.initCanvas({ el: this.$refs.canvas }); }) } }) </script> <style> .canvas-box { width: calc(100% - 68px); height: calc(100% - 180px); margin-bottom: 38px; position: relative; border-radius: 6px; background: #fff; padding: 34px; } .canvas { background: #fff; height: 100%; width: 100%; border: 1px dashed #848588; position: relative; border-radius: 6px; } .saveCanvas, .clearCanvas { padding: 10px 0; background: rgba(207, 225, 245, 1); width: 45%; text-align: center; float: left; color: #3F8EE8; } .saveCanvas { margin-left: 10%; } .sign-page { background: #EDF1F6; width: calc(100% - 60px); height: calc(100% - 96px); padding: 58px 30px 38px; position: fixed; top: 0; left: 0; } .title { text-orientation: mixed; font-size: 18px; color: #A0ACBF; position: absolute; padding: 10%; top: 0; left: 0; } </style> </body> </html>