vue 签名组件
临时帮朋友写个移动端的项目, 发现 它的项目中有个 pdf 文档的 签名功能, 也是折腾了一下签名组件签名组件原理: 利用原生canvas 配合 移动端的事件, touchstart, touchend, touchmove, 进行 在canvas 画布上画线, 最后,把生成的签名, 通过 toDataURL()方法 保存 为 base64 图片,就拿到签名了,实现效果如下:清空画布, ...
·
临时帮朋友写个移动端的项目, 发现 它的项目中有个 pdf 文档的 签名功能, 也是折腾了一下签名组件
签名组件原理: 利用原生canvas 配合 移动端的事件, touchstart, touchend, touchmove, 进行 在canvas 画布上画线, 最后,把生成的签名, 通过 toDataURL()方法 保存 为 base64 图片,就拿到签名了,实现效果如下:
清空画布, 选择签名字体颜色, 保存, 功能比较简单
github上的 签名组件
上代码啊
注: 本项目中使用了 vant-ui, 看演示报错的小伙伴 ,记得删除掉 vant-ui 的组件,然而,你可能看不到 有些效果了,比如字体颜色,清空, 确认等
1. template 模板
<template>
<div class="signHandle">
<canvas ref="signHandle" class="canvas" />
<div class="btn_container van-hairline--top" :style="{height:height + 'px'}">
<van-radio-group v-model="radio" class="radio_container" @change="radioHandle">
<van-radio v-for="item in liColors" :key="item" :checked-color="item" :name="item" />
</van-radio-group>
<div>
<van-button size="mini" @touchstart="clearHandle">清空</van-button>
<van-button type="info" size="mini" @touchstart="saveImg">确认</van-button>
</div>
</div>
</div>
</template>
2. js, 都是 canvas 的 一些 api , 就不解释了
<script>
// 解构设备的宽度, 和 高度
const { clientWidth, clientHeight } = document.documentElement
export default {
data() {
return {
radio: '#000',
height: 50,
direction: false, // true 代表横屏, false 代表'竖屏'
el: '', // canvas dom
ctx: '', // canvas context
background: '#fff', // canvas background-color
color: '#000', // 绘制时线条的颜色
linewidth: 3, // 线条的宽度
liColors: ['#ee0a24', '#000', '#1890ff']
}
},
created() {
this.color = this.radio
window.addEventListener(
'onorientationchange' in window ? 'orientationchange' : 'resize',
() => {
if (window.orientation === 180 || window.orientation === 0) {
this.direction = false
this.draw()
}
if (window.orientation === 90 || window.orientation === -90) {
this.direction = true
this.draw()
}
},
false
)
},
mounted() {
this.draw()
},
methods: {
radioHandle(value) {
this.color = value
this.setCanvas()
},
// 添加绘制 line
draw() {
document.addEventListener('touchmove', e => e.preventDefault(), {
passive: false
})
this.el = this.$refs.signHandle
this.initCanvas()
},
// 初始化canvas配置
initCanvas() {
const { height, direction, el } = this
if (direction) {
el.width = clientHeight
el.height = clientWidth - height
} else {
el.width = clientWidth
el.height = clientHeight - height
}
this.ctx = el.getContext('2d')
this.setCanvas()
this.drawStart()
this.drawing()
this.drawEnd()
},
// 配置 canvas
setCanvas() {
const { ctx, height, direction } = this
console.log(direction)
// 设置背景色
ctx.fillStyle = this.background
// 绘制矩形
if (direction) {
ctx.fillRect(0, 0, clientHeight, clientWidth - height)
} else {
ctx.fillRect(0, 0, clientWidth, clientHeight - height)
}
// 设置线条颜色
ctx.strokeStyle = this.color
// 设置线宽
ctx.lineWidth = this.linewidth
// 设置线条两头的结束点和开始点是圆形的
ctx.lineCap = 'round'
},
// 开始绘制
drawStart() {
const { el, ctx } = this
el.addEventListener(
'touchstart',
e => {
ctx.beginPath()
ctx.moveTo(e.changedTouches[0].pageX, e.changedTouches[0].pageY)
},
false
)
},
// 绘制中
drawing() {
const { el, ctx } = this
el.addEventListener(
'touchmove',
e => {
ctx.lineTo(e.changedTouches[0].pageX, e.changedTouches[0].pageY)
ctx.stroke()
},
false
)
},
// 绘制结束
drawEnd() {
const { el, ctx } = this
el.addEventListener('touchend', () => ctx.closePath(), false)
},
// 清空
clearHandle() {
this.initCanvas()
},
// 保存信息
saveImg() {
const imgBase64 = this.el.toDataURL()
console.log('保存签名成功' + imgBase64)
}
}
}
</script>
3. css
.signHandle {
position: relative;
background-color: #666;
.canvas {
position: absolute;
top: 0;
left: 0;
}
.btn_container {
width: 100%;
position: fixed;
bottom: 0;
left: 0;
background-color: #fff;
display: flex;
align-items: center;
padding: 0 15px;
box-sizing: border-box;
justify-content: space-between;
.radio_container {
display: flex;
/deep/ .van-radio {
margin-right: 10px;
&:nth-child(1) {
/deep/ .van-icon {
background-color: #ee0a24;
}
}
&:nth-child(2) {
/deep/ .van-icon {
background-color: #000;
}
}
&:nth-child(3) {
/deep/ .van-icon {
background-color: #1890ff;
}
}
}
}
}
}
</style>
更多推荐
已为社区贡献20条内容
所有评论(0)