微信小程序用 canvas 实现手写签名弹框(全网最最最详细!!)

一、签字面板效果图

二、WXML文件

🌸点击弹出手写签名面板事件

<van-button type="default" bindtap="handWrittenSign">点击弹出手写签名弹框</van-button>

🌸手写签名面板 Popup 弹出层(vant

<van-popup show="{{ showWritten }}" position="bottom" custom-class="writtenArea" bind:close="writtenSignClose">
    <view class="agree-area">
        <text>请签字以确认同意用户服务协议</text>
    </view>
    <canvas type="3d" canvas-id="myCanvas" bindtouchstart="onTouchStart" bindtouchmove="onTouchMove" bindtouchend="onTouchEnd" class="canvas-area"></canvas>
    <view class="written-btn-area">
        <van-button type="default" custom-class="write" bindtap="resetWrite" size="small">重置</van-button>
        <van-button plain type="info" custom-class="write" bindtap="cancelWrite" size="small">取消</van-button>
        <van-button type="info" custom-class="write" bindtap="confirmWrite" size="small">确认</van-button>
    </view>
</van-popup>

三、JS文件

Page({
	/**
     * 页面的初始数据
     */
    data: {
        showWritten: false,  //展示手写签名弹框
        startX: undefined, // 线条的坐标点
        startY: undefined,
        userSignatureId: undefined, // 签名图片id
        screenWidth: undefined, // 屏幕宽
        screenHeight: undefined, // 屏幕高
    },
	
	/**
     * 事件
     */
	
	// 点击弹出手写签名弹框
	handWrittenSign() {
        this.setData({ showWritten: true });
        this.initCanvas();
    },
	
	// 点击蒙层关闭弹框
	writtenSignClose() {
        this.setData({ showWritten: false });
        this.resetWrite();
    },

	// 初始化画布
	initCanvas() {
        const context = wx.createCanvasContext('myCanvas', this);
        context.setStrokeStyle('#000'); // 设置线条样式
        context.setLineWidth(3); // 线条粗细
        context.setLineCap('round'); // 设置线条端点样式
        context.setLineJoin('round'); // 设置线条交点样式(拐角)
        context.beginPath(); // 开始新的绘制路径
        context.clearRect(0, 0, this.data.startX, this.data.startY); // 清除画布上的内容
        context.draw(); // 绘制到canvas上
    },

	// 手指触摸动作开始
	onTouchStart(e) {
        const context = wx.createCanvasContext('myCanvas', this);

        context.setStrokeStyle('#000000');
        context.setLineWidth(3);

        this.setData({
            'startX': e.touches[0].x,
            'startY': e.touches[0].y,
        })
    },

	// 手指触摸后移动
	onTouchMove(e) {
        const context = wx.createCanvasContext('myCanvas', this);
        
        context.moveTo(this.data.startX, this.data.startY);
        context.lineTo(e.touches[0].x, e.touches[0].y);
        context.stroke();
        context.draw(true);
        
        this.setData({
            'startX': e.touches[0].x,
            'startY': e.touches[0].y,
        })
    },

	// 手指触摸动作结束
	onTouchEnd() {
        const context = wx.createCanvasContext('myCanvas', this);
        context.closePath();
        context.draw(true);
    },

	// 重置签名
    resetWrite() {
        const context = wx.createCanvasContext('myCanvas', this);
        let { screenWidth, screenHeight } = this.data;
        // 清空画布
        context.clearRect(0, 0, screenWidth, screenHeight);
        context.beginPath();
        // 绘制白色背景
        context.setFillStyle('#ffffff'); // 填充色 白色
        context.fillRect(0, 0, screenWidth, screenHeight); // 绘制一个矩形清除画布内容
        context.setLineWidth(3);  // 线条粗细
        // 绘制提示文字(根据需求可要可不要)
        context.setFontSize(14);
        context.setFillStyle('#999999');
        context.setTextAlign('center');
        context.fillText('请在此区域签名', this.data.startX / 2, this.data.startY / 2);
        // 绘制到canvas上
        context.draw();
    },

	// 取消签名
    cancelWrite() {
		this.setData({ 
            showWritten: false
        })
        const context = wx.createCanvasContext('myCanvas', this);
        let { screenWidth, screenHeight } = this.data;
         // 清空画布
        context.clearRect(0, 0, screenWidth, screenHeight);
        context.beginPath();
        context.setFillStyle('#ffffff');
        context.fillRect(0, 0, screenWidth, screenHeight);
        context.setLineWidth(3);
        // 绘制到canvas上
        context.draw();
    },
  
  	// 确认提交
    confirmWrite() {
		this.setData({showWritten: false});  // 关闭手写面板
        wx.canvasToTempFilePath({
            canvasId: 'myCanvas',
            success: function(res) {
              const tempFilePath = res.tempFilePath; // 取图片文件路径
              // 将 tempFilePath 传递给后端接口
    		  uploadFile({fileType: 'image', tempFilePath: tempFilePath})
                .then(file => {
                // 由于签名面板在表单中,提交表单需要传签名文件id,在这里赋值
                    that.setData({ userSignatureId: file.id })
                })
                .catch(err => {
                    console.error(err)
                })
            }
        });
    },  
	
	/**
     * 生命周期函数--监听页面显示
     */
    onShow() {
        // 获取屏幕的宽高 可结合画布在父元素的百分比获取实际宽高度;若画布为固定值,以上所用宽高度可不用在此获取,直接写死即可。
        const systemInfo = wx.getSystemInfoSync();
        this.setData({
            screenWidth: systemInfo.screenWidth,
            screenHeight: systemInfo.screenHeight
        })
    },
})

🌸最后可以使用 canvas 组件的 toTempFilePath 方法将 canvas 画布内容保存为临时文件路径,然后将该路径传递给后端即可。

四、WXSS文件

.writtenArea {
    height: 60%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-direction: column;
}

.canvas-area {
    width: 90%;
    flex: 1;
    border: 1px solid #ccc;
}

.write {
    width: 180rpx;
}

.written-btn-area {
    width: 100%;
    display: flex;
    justify-content: space-between;
    padding: 0 40rpx;
    margin-top: 20rpx;
}

.agree-area {
    width: 90%;
    margin: 20rpx 0;
    text-align: left;
    font-size: 36rpx;
    font-weight: 700;
}

五、小Tips ~

💡 文中触摸板的方法中多次获取canvas的上下文,即const context = wx.createCanvasContext('myCanvas', this);,我这里是直接在函数内部定义方法,内部使用。也可全局定义,使用wx.createCanvasContext 获取绘图上下文 context全局使用,如下:

Page({
  data: {
    canvasContext: null // canvas上下文对象
  },
  
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    this.data.canvasContext = wx.createCanvasContext('myCanvas', this);
  },
  // ...
})

六、IOS会遇到的问题及如何解决

🌸微信小程序给出的解决方案:
在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
是的,微信小程序可以使用Canvas实现签名功能。具体实现方法如下: 1. 在wxml文件中添加一个canvas元素: ```html <canvas canvas-id="myCanvas" style="width: 100%; height: 100%;" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd"></canvas> ``` 2. 在js文件中定义相关的变量和函数: ```javascript // 定义画布上下文 let context = null; // 定义画笔颜色和粗细 let penColor = "#000000"; let penWidth = 2; // 定义画笔是否正在使用 let isPainting = false; // 定义画笔起始点位置 let lastX = 0; let lastY = 0; // 获取画布上下文 context = wx.createCanvasContext("myCanvas"); // 触摸开始函数 function touchStart(event) { isPainting = true; lastX = event.touches[0].x; lastY = event.touches[0].y; } // 触摸移动函数 function touchMove(event) { if (isPainting) { let currentX = event.touches[0].x; let currentY = event.touches[0].y; context.beginPath(); context.moveTo(lastX, lastY); context.lineTo(currentX, currentY); context.setStrokeStyle(penColor); context.setLineWidth(penWidth); context.stroke(); context.closePath(); lastX = currentX; lastY = currentY; context.draw(true); } } // 触摸结束函数 function touchEnd() { isPainting = false; } ``` 3. 在wxml文件中添加按钮来保存签名: ```html <button type="primary" bindtap="save">保存</button> ``` 4. 在js文件中定义保存签名的函数: ```javascript // 保存签名函数 function save() { wx.canvasToTempFilePath({ canvasId: "myCanvas", success: function(res) { wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success(res) { wx.showToast({ title: "保存成功", icon: "success", duration: 2000 }); }, fail(res) { wx.showToast({ title: "保存失败", icon: "none", duration: 2000 }); } }); }, fail: function (res) { console.log(res); } }); } ``` 这样就可以在微信小程序实现签名功能了。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值