通过原生canvas实现,我这篇是对其进行了改造,并用在vue项目中,并且增加了浏览器改变画板可以达到一个自适应,签名完成之后,可以拿到图片的blob对象、以及base64编码等,根据需求适当选择,直接上代码吧:
我将 签名画板单独封装为一个组件,在需要的地方引入即可,注意要给外层容器一个宽高,该组件默认为宽高都为100%
<template>
<div style="width: 100%;height: 100%;">
<div class="drawing-board">
<canvas id="canvas"></canvas>
</div>
<div class="tool-bar">
<el-button @click="reset()" size="small" type="primary">清除</el-button>
<el-button @click="save()" size="small" type="success">确定</el-button>
</div>
</div>
</template>
<script>
const $ = name => document.querySelector(name)
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent))
const config = {
width: 0,
height: 0,
lineWidth: 5,
strokeStyle: 'red',
lineCap: 'round',
lineJoin: 'round',
}
const client = {
offsetX: 0,
offsetY: 0
}
let canvas,ctx;
export default {
mounted(){
this.drawingBoardInit()
},
destroyed() {
window.removeEventListener(mobileStatus ? "touchstart" : "mousedown", this.init)
window.removeEventListener(mobileStatus ? "touchend" : "mouseup", this.cloaseDraw)
window.removeEventListener('resize', this.resetSize)
},
methods:{
drawingBoardInit() {
const { width, height, left, top } = $('.drawing-board').getBoundingClientRect()
config.width = width
config.height = height
client.offsetX = left
client.offsetY = top
canvas = $('#canvas')
canvas.width = config.width
canvas.height = config.height
canvas.style.border = '1px solid #000'
ctx = canvas.getContext('2d')
ctx.fillStyle = 'transparent'
ctx.fillRect(
0,
0,
config.width,
config.height
);
window.addEventListener(mobileStatus ? "touchstart" : "mousedown", this.init)
window.addEventListener(mobileStatus ? "touchend" : "mouseup", this.cloaseDraw)
window.addEventListener('resize', this.resetSize)
},
init(event) {
const { clientX, clientY } = mobileStatus ? event.changedTouches[0] : event
ctx.beginPath()
ctx.lineWidth = config.lineWidth
ctx.strokeStyle = config.strokeStyle
ctx.lineCap = config.lineCap
ctx.lineJoin = config.lineJoin
ctx.moveTo(clientX - client.offsetX, clientY - client.offsetY)
window.addEventListener(mobileStatus ? "touchmove" : "mousemove", this.draw)
},
draw(event) {
const { clientX, clientY } = mobileStatus ? event.changedTouches[0] : event
ctx.lineTo(clientX - client.offsetX, clientY - client.offsetY)
ctx.stroke()
},
cloaseDraw() {
ctx.closePath()
window.removeEventListener("mousemove", this.draw)
},
reset() {
ctx.clearRect(0, 0, config.width, config.height)
},
save() {
let imgBase64 = canvas.toDataURL('png')
console.log(imgBase64, 'imgBase64-->>')
canvas.toBlob(blob => {
console.log(blob, 'blob-->>')
const date = new Date().getTime()
const link = document.createElement('a')
link.download = `${date}.png`
link.href = URL.createObjectURL(blob)
link.click()
link.remove()
})
},
resetSize() {
const { width, height, left, top } = $('.drawing-board').getBoundingClientRect()
const dx = Math.abs(left - client.offsetX)
const dy = Math.abs(top - client.offsetY)
config.width = width
config.height = height
client.offsetX = left
client.offsetY = top
const canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height)
canvas.width = width
canvas.height = height
ctx.putImageData(canvasData, dx, dy)
}
}
}
</script>
<style scoped>
.drawing-board {
width: 100%;
height: calc(100% - 40px);
border-bottom: 1px solid #ccc;
box-sizing: border-box;
}
.tool-bar {
width: 100%;
height: 40px;
display: flex;
justify-content: flex-end;
align-items: center;
}
</style>