vue 签名组件

临时帮朋友写个移动端的项目, 发现 它的项目中有个 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>

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值