前端微信小程序签名生成

文章详细描述了如何在微信小程序中使用签名组件,通过CanvasAPI进行手写签名,并将签名图片转换为Base64格式发送给后端,以及处理用户重签和保存图片至临时文件路径并上传的功能实现。
摘要由CSDN通过智能技术生成

1、签名组件(思路是使用canvas 转换成base64图片 返给后端 之后 获取的时候 后端再把当前存储的 路径返回)

const app = getApp();
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 高度百分比
    h: {
      type: Number,
      value: 0.2,
    },
    //  填充描述文字
    fillText: {
      type: String,
      value: "请使用正楷",
    },
  },

  /**
   * 组件的初始数据
   */
  data: {
    canvas: "",
    ctx: "",
    pr: 0,
    width: '',
    height: '',
    first: true,
  },
  attached: function () {
    this.getSystemInfo();
    this.createCanvas();
  },
  ready() {
  },
  /**
   * 组件的方法列表
   */
  methods: {
    start(e) {
      if (this.data.first) {
        this.clearClick();
        this.setData({ first: false });
      }
      // 开始创建一个路径,如果不调用该方法,最后无法清除画布
      this.data.ctx.beginPath();
      // 把路径移动到画布中的指定点,不创建线条。用 stroke 方法来画线条
      this.data.ctx.moveTo(e.changedTouches[0].x, e.changedTouches[0].y);
    },
    move(e) {
      // 增加一个新点,然后创建一条从上次指定点到目标点的线。用 stroke 方法来画线条
      this.data.ctx.lineTo(e.changedTouches[0].x, e.changedTouches[0].y);
      this.data.ctx.stroke();
    },
    error: function (e) {
      console.log("画布触摸错误" + e);
    },
    /**
     * 初始化
     */
    createCanvas() {
      const pr = this.data.pr; // 像素比
      const query = this.createSelectorQuery();
      query
        .select("#canvas")
        .fields({ node: true, size: true })
        .exec((res) => {
          const canvas = res[0].node;
          console.log(res[0],'res[0]')
          const ctx = canvas.getContext("2d");
          canvas.width = this.data.width * pr; // 画布宽度
          canvas.height = this.data.height * pr; // 画布高度
          ctx.scale(pr, pr); // 缩放比
          ctx.lineGap = "round";
          ctx.lineJoin = "round";
          ctx.lineWidth = 4; // 字体粗细
          ctx.font = "40px Arial"; // 字体大小,
          ctx.fillStyle = "#ecf0ef"; // 填充颜色
          ctx.fillText(
            this.data.fillText,
            this.data.width / 2 - 100,
            this.data.height / 2
          );
          this.setData({ ctx, canvas });
        });

    },
    // 获取系统信息,宽,高,像素比
    getSystemInfo() {
      let _that = this;
      wx.getSystemInfo({
        success(res) {
            console.log(res,'getSystemInfo')
          _that.setData({
            pr: res.pixelRatio,
            width: res.windowWidth,
            height: res.windowHeight * _that.data.h ,
          });
        },
      });
    },
    //重签
    clearClick: function () {
      //清除画布
      this.data.first = true;
      this.data.ctx.clearRect(0, 0, this.data.width, this.data.height);
    },
    //保存图片
    saveClick: function (cb) {
      if (this.data.first) {
        wx.showToast({
          title: "签名数据为空!",
          icon: "none",
        });
        return false;
      }
      //  获取临时文件路径
      wx.canvasToTempFilePath({
        x: 0,
        y: 0,
        width: this.data.width,
        height: this.data.height,
        destWidth: this.data.width * this.data.pr,
        destHeight: this.data.height * this.data.pr,
        canvasId: "canvas",
        canvas: this.data.canvas,
        fileType: "png",
        success: (res) => {
            cb && cb(res);
        //       //  转换成功派发事件
            this.triggerEvent("success", res);

            // 如果需要使用base64的可以使用下面的,此处只用临时路径,注释掉这个功能
          // 文件转base64
        //   wx.getFileSystemManager().readFile({
        //     filePath: res.tempFilePath,
        //     encoding: "base64",
        //     success: (val) => {
        //       cb && cb(val,res);
        //       //  转换成功派发事件
        //       this.triggerEvent("success", val.data);
        //     },
        //   });
        },
      });
    },
  },
});

<view class="signatureView">
    <canvas type="2d" id="canvas" bindtouchmove="move" bindtouchstart="start" binderror="error" style="width:{{width}}px;height:{{height}}px;"
    force-use-old-canvas="true">
    </canvas>
</view>
 saveSignature(){
        let _this=this;
        let signature = this.selectComponent('.signature');
        signature.saveClick((result)=>{
             //图片上传
        wx.showLoading({
            title: '上传中...',
            onLoad: true,
            mask: true
        })
        wx.uploadFile({
            url: app.data.upfileDomainName,
            filePath:result.tempFilePath,
            name: 'file',
            formData: {},
            header: {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + wx.getStorageSync('access_token')
            },
            success(res) {
                var dataInfo = JSON.parse(res.data);
                if (res.statusCode == 200 && dataInfo.status*1===200) {
                    _this.setData({
                        ['audit.signatureFilePath']:dataInfo.data[0].fileNewName,
                        previewPath:dataInfo.data[0].url,
                    })
                    _this.onCloseSignature()
                } else {
                    _this._Toast('上传失败');
                }
                wx.hideLoading({noConflict: true}) 
            },
            fail(err) {
                console.log(err, '图片上传失败')
                wx.hideLoading({noConflict: true}) 
                _this._Toast('上传失败');
            }
        })
            
        })
    },

2、完整代码

  //这个是 编写的时候
  <van-field
            label="签名"
            readonly
            required
            title-width="100%"
            border="{{ false }}"
        />
        <view class="bg-white padding15">
            <view class="ww-flex flex-col col-ct row-ct" style="background: #F7F8FA;height:140px" data-qmuser="ywclqm" bindtap="openSignature">
                <image wx:if="{{!audit.signatureFilePath}}" src="./img/icon_qm.png" style="width:36px;height:36px"></image>
                <view wx:if="{{!audit.signatureFilePath}}" style="padding-top:5px;color:#4E5969">点此签名</view>
                <image wx:if="{{audit.signatureFilePath}}" src="{{previewPathName}}{{previewPath}}" style="width:100%;height:140px"></image>
            </view>
        </view>
//编写打开弹窗
<van-popup closeable  show="{{ show }}" position="bottom" z-index="35" custom-style="width:100%;height: 50%"   bind:close="onCloseSignature">
    <view class="WH ww-flex flex-col" wx:if="{{show}}">
        <view class="flex1">
            <signature  h="{{0.4}}" class="signature" /> //组件
        </view>
        <view class="flex-none ww-flex flex-row  paddingLR15">
            <view class="flex1 textCenter signatureBtn marginR20"  bindtap="resetSignature">重置</view>
            <view class="flex1 textCenter signatureBtn"  bindtap="saveSignature">确认</view>
        </view> 
    </view>
</van-popup>

 

3.组件内容(画布)

<view class="signatureView">
    <canvas type="2d" id="canvas" bindtouchmove="move" bindtouchstart="start" binderror="error" style="width:{{width}}px;height:{{height}}px;"
    force-use-old-canvas="true">
    </canvas>
</view>

4、画布js

const app = getApp();
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 高度百分比
    h: {
      type: Number,
      value: 0.2,
    },
    //  填充描述文字
    fillText: {
      type: String,
      value: "请使用正楷",
    },
  },

  /**
   * 组件的初始数据
   */
  data: {
    canvas: "",
    ctx: "",
    pr: 0,
    width: '',
    height: '',
    first: true,
  },
  attached: function () {
    this.getSystemInfo();
    this.createCanvas();
  },
  ready() {
  },
  /**
   * 组件的方法列表
   */
  methods: {
    start(e) {
      if (this.data.first) {
        this.clearClick();
        this.setData({ first: false });
      }
      // 开始创建一个路径,如果不调用该方法,最后无法清除画布
      this.data.ctx.beginPath();
      // 把路径移动到画布中的指定点,不创建线条。用 stroke 方法来画线条
      this.data.ctx.moveTo(e.changedTouches[0].x, e.changedTouches[0].y);
    },
    move(e) {
      // 增加一个新点,然后创建一条从上次指定点到目标点的线。用 stroke 方法来画线条
      this.data.ctx.lineTo(e.changedTouches[0].x, e.changedTouches[0].y);
      this.data.ctx.stroke();
    },
    error: function (e) {
      console.log("画布触摸错误" + e);
    },
    /**
     * 初始化
     */
    createCanvas() {
      const pr = this.data.pr; // 像素比
      const query = this.createSelectorQuery();
      query
        .select("#canvas")
        .fields({ node: true, size: true })
        .exec((res) => {
          const canvas = res[0].node;
          console.log(res[0],'res[0]')
          const ctx = canvas.getContext("2d");
          canvas.width = this.data.width * pr; // 画布宽度
          canvas.height = this.data.height * pr; // 画布高度
          ctx.scale(pr, pr); // 缩放比
          ctx.lineGap = "round";
          ctx.lineJoin = "round";
          ctx.lineWidth = 4; // 字体粗细
          ctx.font = "40px Arial"; // 字体大小,
          ctx.fillStyle = "#ecf0ef"; // 填充颜色
          ctx.fillText(
            this.data.fillText,
            this.data.width / 2 - 100,
            this.data.height / 2
          );
          this.setData({ ctx, canvas });
        });

    },
    // 获取系统信息,宽,高,像素比
    getSystemInfo() {
      let _that = this;
      wx.getSystemInfo({
        success(res) {
            console.log(res,'getSystemInfo')
          _that.setData({
            pr: res.pixelRatio,
            width: res.windowWidth,
            height: res.windowHeight * _that.data.h ,
          });
        },
      });
    },
    //重签
    clearClick: function () {
      //清除画布
      this.data.first = true;
      this.data.ctx.clearRect(0, 0, this.data.width, this.data.height);
    },
    //保存图片
    saveClick: function (cb) {
      if (this.data.first) {
        wx.showToast({
          title: "签名数据为空!",
          icon: "none",
        });
        return false;
      }
      //  获取临时文件路径
      wx.canvasToTempFilePath({
        x: 0,
        y: 0,
        width: this.data.width,
        height: this.data.height,
        destWidth: this.data.width * this.data.pr,
        destHeight: this.data.height * this.data.pr,
        canvasId: "canvas",
        canvas: this.data.canvas,
        fileType: "png",
        success: (res) => {
            cb && cb(res);
        //       //  转换成功派发事件
            this.triggerEvent("success", res);

            // 如果需要使用base64的可以使用下面的,此处只用临时路径,注释掉这个功能
          // 文件转base64
        //   wx.getFileSystemManager().readFile({
        //     filePath: res.tempFilePath,
        //     encoding: "base64",
        //     success: (val) => {
        //       cb && cb(val,res);
        //       //  转换成功派发事件
        //       this.triggerEvent("success", val.data);
        //     },
        //   });
        },
      });
    },
  },
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值