使用Vue、Canvas、ElementUI實現的電子簽字版,PC和移動端皆可用。效果如下:
HTML
<template> <section class="signature"> <div class="signatureBox"> <div class="canvasBox" ref="canvasHW"> <canvas ref="canvasF" @touchstart='touchStart' @touchmove='touchMove' @touchend='touchEnd' @mousedown="mouseDown" @mousemove="mouseMove" @mouseup="mouseUp"></canvas> <p style="margin:0 0 10px;line-height:20px;color:#999;">注:重寫后請重新上傳簽名</p> <div class="btnBox"> <el-button size="small" type="primary" @click="overwrite">重寫</el-button> <el-button size="small" type="primary" @click="commit">上傳並預覽</el-button> </div> </div> </div> <img class="imgCanvas" :src="imgUrl"> </section> </template>
JS
<script> export default { data () { return { stageInfo: '', imgUrl: '', client: {}, points: [], canvasTxt: null, startX: 0, startY: 0, moveY: 0, moveX: 0, endY: 0, endX: 0, w: null, h: null, isDown: false, isViewAutograph: this.$route.query.isViews > 0, contractSuccess: this.$route.query.contractSuccess } }, mounted () { // 找到 <canvas> 元素 let canvas = this.$refs.canvasF canvas.height = this.$refs.canvasHW.offsetHeight - 87 canvas.width = this.$refs.canvasHW.offsetWidth - 2 // 創建 context 對象 this.canvasTxt = canvas.getContext('2d') this.stageInfo = canvas.getBoundingClientRect() }, methods: { //mobile touchStart (ev) { ev = ev || event ev.preventDefault() if (ev.touches.length == 1) { let obj = { x: ev.targetTouches[0].clienX, y: ev.targetTouches[0].clientY, } this.startX = obj.x this.startY = obj.y this.canvasTxt.beginPath() this.canvasTxt.moveTo(this.startX, this.startY) this.canvasTxt.lineTo(obj.x, obj.y) this.canvasTxt.stroke() this.canvasTxt.closePath() this.points.push(obj) } }, touchMove (ev) { ev = ev || event ev.preventDefault() if (ev.touches.length == 1) { let obj = { x: ev.targetTouches[0].clientX - this.stageInfo.left, y: ev.targetTouches[0].clientY - this.stageInfo.top } this.moveY = obj.y this.moveX = obj.x this.canvasTxt.beginPath() this.canvasTxt.moveTo(this.startX, this.startY) this.canvasTxt.lineTo(obj.x, obj.y) this.canvasTxt.stroke() this.canvasTxt.closePath() this.startY = obj.y this.startX = obj.x this.points.push(obj) } }, touchEnd (ev) { ev = ev || event ev.preventDefault() if (ev.touches.length == 1) { let obj = { x: ev.targetTouches[0].clientX - this.stageInfo.left, y: ev.targetTouches[0].clientY - this.stageInfo.top } this.canvasTxt.beginPath() this.canvasTxt.moveTo(this.startX, this.startY) this.canvasTxt.lineTo(obj.x, obj.y) this.canvasTxt.stroke() this.canvasTxt.closePath() this.points.push(obj) } }, //pc mouseDown (ev) { ev = ev || event ev.preventDefault() if (1) { // 鼠標相對於事件源元素(srcElement)的X,Y坐標 let obj = { x: ev.offsetX, y: ev.offsetY } this.startX = obj.x this.startY = obj.y // 起始一條路徑,或重置當前路徑 this.canvasTxt.beginPath() // 把路徑移動到畫布中的指定點,不創建線條 this.canvasTxt.moveTo(this.startX, this.startY) // 添加一個新點,然后在畫布中創建從該點到最后指定點的線條 this.canvasTxt.lineTo(obj.x, obj.y) // 繪制已定義的路徑 this.canvasTxt.stroke() // 創建從當前點回到起始點的路徑 this.canvasTxt.closePath() this.points.push(obj) this.isDown = true } }, mouseMove (ev) { ev = ev || event ev.preventDefault() if (this.isDown) { let obj = { x: ev.offsetX, y: ev.offsetY } this.moveY = obj.y this.moveX = obj.x this.canvasTxt.beginPath() this.canvasTxt.moveTo(this.startX, this.startY) this.canvasTxt.lineTo(obj.x, obj.y) this.canvasTxt.stroke() this.canvasTxt.closePath() this.startY = obj.y this.startX = obj.x this.points.push(obj) } }, mouseUp (ev) { ev = ev || event ev.preventDefault() if (1) { let obj = { x: ev.offsetX, y: ev.offsetY } this.canvasTxt.beginPath() this.canvasTxt.moveTo(this.startX, this.startY) this.canvasTxt.lineTo(obj.x, obj.y) this.canvasTxt.stroke() this.canvasTxt.closePath() this.points.push(obj) this.points.push({ x: -1, y: -1 }) this.isDown = false } }, //重寫 overwrite () { this.canvasTxt.clearRect(0, 0, this.$refs.canvasF.width, this.$refs.canvasF.height) this.points = [] this.imgUrl = "" }, //提交簽名 commit () { this.imgUrl = this.$refs.canvasF.toDataURL(); } } } </script>
CSS
<style scoped> .signatureBox { width: 100%; height: calc(100% - 50px); box-sizing: border-box; overflow: hidden; background: #fff; z-index: 100; display: flex; flex-direction: column; } .canvasBox { box-sizing: border-box; flex: 1; } canvas { border: 1px solid #dcdfe6; border-radius: 4px; box-sizing: border-box; } </style>