用uniapp实现微信小程序的电子签名效果

简介: 用uniapp实现微信小程序的电子签名效果

画布可以做很多事情,比如可以绘图,也可以做海报。在这里只是想拿它来的实现亲笔签名,开启不一样的亲笔签名姿势。


开发框架:uniapp

开发语言:vue2

展示平台:微信小程序(实际可以兼容多个平台)


标签和样式没什么好说的,这里绘制了简单的页面,见下图:

8a55c7b06dc64d348f35bf2e9e157577.jpg


1、标签和样式

<template>
  <view class="page-content">
  <view class="form">
    <view class="form-content">
    <canvas class="form-content__canvas" canvas-id="canvas_sign" @touchstart="touchstart"
      @touchmove="touchmove" @touchend="touchend" disable-scroll="true"></canvas>
    </view>
    <view class="form-footer">
    <button class="form-footer__reset" @click="autographClick(1)">重置</button>
    <button class="form-footer__save" @click="autographClick(2)">保存</button>
    <button class="form-footer__preview" @click="autographClick(3)">预览</button>
    </view>
  </view>
  </view>
</template>
<style lang="scss" scoped>
  /*
  * 横屏后的适配方案
  * @param $rpx为需要转换的字号
  * @参考 https://blog.csdn.net/sdfsfsdscd/article/details/91375066
  **/
  @function tovmin($rpx) {
  @return #{$rpx * 100 / 750}vmin;
  }
  .page-content {
  width: 100vw;
  height: 100vh;
  .form {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    .form-content {
    width: 100%;
    height: 100%;
    &__canvas {
      height: calc(100vh - tovmin(20) - tovmin(120) - constant(safe-area-inset-bottom));
      height: calc(100vh - tovmin(20) - tovmin(120) - env(safe-area-inset-bottom));
      width: 100vw;
    }
    }
    .form-footer {
    padding-top: tovmin(20);
    height: calc(tovmin(120) + constant(safe-area-inset-bottom));
    height: calc(tovmin(120) + env(safe-area-inset-bottom));
    width: 100%;
    display: flex;
    flex-direction: row;
    background: #FFFFFF;
    box-shadow: 0 tovmin(4) tovmin(20) tovmin(2) rgba(183, 183, 183, 0.20);
    button {
      width: 20vw;
      height: tovmin(88);
      line-height: tovmin(88);
      border-radius: tovmin(48);
      text-align: center;
      font-size: tovmin(36);
      font-weight: bold;
    }
    button::after {
      border: none;
    }
    &__reset {
      color: #008AFE;
      border: tovmin(1) solid #008AFE;
    }
    &__save {
      background-image: linear-gradient(135deg, #1BC5FF 0%, #008AFE 100%);
    }
    &__preview {
      color: #008AFE;
      border: tovmin(1) solid #008AFE;
    }
    }
  }
  }
</style>


2、横屏切换

到【pages.json】文件中添加横屏切换配置

注意:不同的平台横屏切换将有所不一样。这里是针对微信小程序的横屏适配


{
  "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
  {
    "path": "pages/index/index",
    "style": {
    "navigationBarTitleText": "亲笔签名",//导航栏标题
    "pageOrientation": "landscape",//切换横屏
    "enablePullDownRefresh": false,//关闭下拉刷新
    "disableScroll": true // 整体页面禁止上下滑动
    }
  }
  ],
  "globalStyle": {
  "navigationBarTextStyle": "black",
  "navigationBarBackgroundColor": "#FFFFFF",
  "backgroundColor": "#f5f5f5",
  "navigationStyle": "default", // default/custom。custom即取消默认的原生导航栏
  "mp-alipay": {
    "transparentTitle": "always",
    "titlePenetrate": "YES"
  }
  }
}


然后是绘制逻辑处理,注意点在代码中备注:


3、绘图

3.1、初始化数据会吧?

 

data() {
    return {
    canvasCtx: '', //绘图图像
    points: [], //路径点集合
    hasSign: false,
    isInit: false,
    }
  },
  onLoad(query) {
    this.canvasCtx = uni.createCanvasContext('canvas_sign', this) //创建绘图对象
    //设置画笔样式
    this.canvasCtx.lineWidth = 6
    // 设置线条的端点样式
    this.canvasCtx.lineCap = 'round'
    // 设置线条的交点样式
    this.canvasCtx.lineJoin = 'round'
  },


3.2、触摸开始时获取起点,会吧?

touchstart: function(e) {
    if (!this.isInit) {
      this.isInit = true
      this.autographClick(1);
    }
    let startX = e.changedTouches[0].x
    let startY = e.changedTouches[0].y
    let startPoint = {
      X: startX,
      Y: startY
    }
    this.points.push(startPoint)
    //每次触摸开始,开启新的路径
    this.canvasCtx.beginPath()
    },


3.3、触摸移动获取路径点,会吧?

touchmove: function(e) {
    let moveX = e.changedTouches[0].x
    let moveY = e.changedTouches[0].y
    let movePoint = {
      X: moveX,
      Y: moveY
    }
    this.points.push(movePoint) //存点
    let len = this.points.length
    if (len >= 2) {
      this.draw() //绘制路径
    }
    },


3.4、触摸结束,将未绘制的点清空防止对后续路径产生干扰,简单吧?

touchend: function() {
    this.points = []
    this.canvasCtx.draw(true)
    },


3.5、绘制笔迹,没得问题吧?

这里有几个注意点:


1.为保证笔迹实时显示,必须在移动的同时绘制笔迹

2.为保证笔迹连续,每次从路径集合中区两个点作为起点(moveTo)和终点(lineTo)

3.将上一次的终点作为下一次绘制的起点(即清除第一个点)


draw: function() {
    let point1 = this.points[0]
    let point2 = this.points[1]
    this.points.shift()
    this.canvasCtx.moveTo(point1.X, point1.Y)
    this.canvasCtx.lineTo(point2.X, point2.Y)
    this.canvasCtx.stroke()
    this.canvasCtx.draw(true)
    this.hasSign = true
    },


4、扫尾处理

上面的实现了,说明就可以签下你大名了。这里扫尾工作(按钮点击功能实现)只是景上添花。根据实际情况不一定要做。


<script>
  export default {
  methods: {
    // 底部按钮点击操作
    autographClick(type) {
    let that = this
    if (type === 1) {
      //清空画布
      this.hasSign = false
      uni.getSystemInfo({
      success: function(res) {
        let canvas = uni.createSelectorQuery().select('.form-content__canvas')
        canvas.boundingClientRect().exec(function(data) {
        console.log('canvas', data)
        console.log('canvas wh:' + data[0].width + 'X' + data[0].height)
        let canvasw = Math.ceil(data[0].width)
        let canvash = Math.ceil(data[0].height)
        that.canvasCtx.fillStyle = '#fff'
        that.canvasCtx.fillRect(0, 0, canvasw, canvash)
        that.canvasCtx.draw(true)
        })
      }
      })
    } else {
      if (!this.hasSign) {
      uni.showToast({
        title: '签名不能为空',
        icon: 'none',
        duration: 2000
      })
      return
      }
      uni.getSystemInfo({
      success: function(res) {
        let canvas = uni.createSelectorQuery().select('.form-content__canvas')
        canvas.boundingClientRect().exec(function(data) {
        console.log('canvas saveSign:', data[0].width + 'X' + data[0].height)
        let canvasw = Math.ceil(data[0].width)
        let canvash = Math.ceil(data[0].height)
        uni.canvasToTempFilePath({
          destWidth: canvasw,
          destHeight: canvash,
          fileType: 'jpg',
          canvasId: 'canvas_sign',
          success: function(res) {
          console.log('图片导出成功:', res)
          let path = res.tempFilePath
          // 保存图片
          if (type === 2) {
            that.uploadPic(path)
          } else if (type === 3) {
            // 预览图片
            uni.previewImage({
            urls: [path]
            })
          }
          },
          fail: (err) => {
          // http://tmp/2LVQyvzddk2R820a9009dff43323d8e7fc9ef7a8d076.jpg
          console.log('图片导出失败:', err)
          }
        })
        })
      }
      })
    }
    },
    // 图片上传处理
    uploadPic(tempFile) {
    // 1、将本地图片上传到服务器(假装是七牛云服务器)
    // 2、将七牛云返回的链接,上传到我们的服务器平台
    console.log("------:", tempFile);
    uni.showLoading({
      title: '正在上传中...'
    })
    setTimeout(() => {
      uni.showToast({
      title: '假装签名上传成功',
      duration: 2000,
      icon: 'none'
      });
    }, 1000);
    }
  }
  }
</script>


demo地址:

1、CSDN资源库地:https://download.csdn.net/download/weixin_38633659/85343244

2、gitee地址:https://gitee.com/chenzm_186/autograph-mini.git


相关文章
|
1月前
|
小程序 安全 JavaScript
从零开始uniapp微信小程序项目到发布(超级详细)
最近微信小程序又掀起一波风潮,本文站在新手的角度出发,比较适合第一次使用uniapp 开发微信小程序的伙伴,或者没有过实战经验的小伙伴参考,从零搭建uniapp小程序项目
125 1
|
1月前
|
小程序 前端开发 JavaScript
uniapp转微信小程序编译报错 Bad attr `data-event-opts` with message
uniapp转微信小程序编译报错 Bad attr `data-event-opts` with message
|
2月前
|
开发工具 数据安全/隐私保护 UED
Uniapp 微信登录流程解析
Uniapp 微信登录流程解析
47 0
|
1月前
|
小程序 前端开发 UED
详细讲解uniapp转小程序分包教程!!!
详细讲解uniapp转小程序分包教程!!!
|
2月前
|
开发框架 JavaScript 小程序
uniapp、vue、小程序、js图片转base64 示例代码
uniapp、vue、小程序、js图片转base64 示例代码
|
2月前
|
数据采集 机器学习/深度学习 移动开发
uniapp+springboot医院智能导诊系统源码,自动兼容小程序与H5版本
技术架构:Uniapp+springboot+redis+mybatis plus+mysql+RocketMQ
62 0
|
3月前
|
小程序
基于Uniapp+SpringBoot+Vue的电影交流平台小程序设计与实现(源码+lw+部署文档+讲解等)
基于Uniapp+SpringBoot+Vue的电影交流平台小程序设计与实现(源码+lw+部署文档+讲解等)
50 0
基于Uniapp+SpringBoot+Vue的电影交流平台小程序设计与实现(源码+lw+部署文档+讲解等)
|
3月前
|
存储 小程序 API
uniapp项目实战第五章:小程序Pinia持久化
uniapp项目实战第五章:小程序Pinia持久化
81 0
|
3月前
|
小程序
uniapp 微信小程序登录 新手专用 引入即可
uniapp 微信小程序登录 新手专用 引入即可
31 0
|
3月前
|
小程序 数据安全/隐私保护
uniapp微信隐私保护弹出框 隐私协议弹出框
uniapp微信隐私保护弹出框 隐私协议弹出框
123 0