Skip to content

小程序Canvas签名

在 uni-app 中使用 canvas 实现用户签名绘制的关键在于正确初始化 canvas、捕获触摸事件并实时将用户的绘制轨迹呈现出来。下面详细描述整个过程:


1. 页面结构与 canvas 组件

首先,在页面模板中添加 canvas 元素,并绑定触摸事件。示例代码如下:

html
<template>
    <view class="signature-container">
        <!-- canvas 用于用户签名绘制 -->
        <canvas
            id="signature"
            canvas-id="signature"
            class="signature-canvas"
            @touchstart="startDrawing"
            @touchmove="continueDrawing"
            @touchend="endDrawing"
        >
        </canvas>
        <!-- 可选:清除和保存按钮 -->
        <view class="button-group">
            <view class="btn" @click="clearCanvas">清除</view>
            <view class="btn" @click="saveSignature">保存</view>
        </view>
    </view>
</template>

说明

  • 使用 @touchstart@touchmove@touchend 分别监听触摸开始、移动和结束事件。
  • 样式部分需要设置 canvas 的尺寸和位置,确保用户手指在上面滑动时能正确捕获。

2. Canvas 初始化

在组件的逻辑部分,需要获取 canvas 节点并初始化 2D 绘图上下文。考虑到不同设备的像素比(dpr),需要对 canvas 进行适配。

js
export default {
    data() {
        return {
            ctx: null, // canvas 的 2d 绘图上下文
            isDrawing: false, // 标识当前是否在绘制中
            lastX: 0, // 上一次触摸的 X 坐标
            lastY: 0, // 上一次触摸的 Y 坐标
            dpr: 1 // 设备像素比
        };
    },
    mounted() {
        // 使用 uni.createSelectorQuery 获取 canvas 节点及尺寸
        uni.createSelectorQuery()
            .select('#signature')
            .fields({ node: true, size: true })
            .exec((res) => {
                const canvas = res[0].node;
                // 获取设备像素比
                this.dpr = uni.getSystemInfoSync().pixelRatio;
                // 设置 canvas 的实际宽高,确保在高清屏上显示清晰
                canvas.width = res[0].width * this.dpr;
                canvas.height = res[0].height * this.dpr;
                // 获取 2D 绘图上下文,并做缩放处理
                this.ctx = canvas.getContext('2d');
                this.ctx.scale(this.dpr, this.dpr);
                // 设置默认绘制样式
                this.ctx.lineCap = 'round';
                this.ctx.lineWidth = 2;
                this.ctx.strokeStyle = '#000';
            });
    },
    methods: {
        // 后续在此处添加事件处理函数
    }
};

注意

  • uni.getSystemInfoSync().pixelRatio 用于获取设备像素比;
  • 调整 canvas 的宽高和对上下文进行缩放,可以避免模糊问题。

3. 处理触摸事件

3.1 开始绘制(touchstart)

当用户开始触摸 canvas 时,记录初始点,并调用 beginPath 开始一条新路径。

js
function startDrawing(e) {
    // 设置正在绘制标识为 true
    this.isDrawing = true;
    const touch = e.touches[0];
    // 记录初始触摸点(注意乘以 dpr 以保持一致性)
    this.lastX = touch.x;
    this.lastY = touch.y;
    // 开启一条新路径,并移动到起始点
    this.ctx.beginPath();
    this.ctx.moveTo(this.lastX, this.lastY);
}
// 后续添加 continueDrawing 与 endDrawing

3.2 绘制过程(touchmove)

在用户滑动手指时,不断获取当前触摸点,并用 lineTo 连接上一个点,从而形成连续线条。

js
function continueDrawing(e) {
    if (!this.isDrawing) return;
    const touch = e.touches[0];
    const x = touch.x;
    const y = touch.y;
    // 绘制从上一个点到当前点的直线
    this.ctx.lineTo(x, y);
    this.ctx.stroke();
    // 更新上一个触摸点为当前点
    this.lastX = x;
    this.lastY = y;
}

3.3 结束绘制(touchend)

当触摸结束时,将绘制标识设为 false,结束当前路径。

js
function endDrawing(e) {
    this.isDrawing = false;
    // 可选:这里可对绘制轨迹进行平滑处理或存储轨迹数据
}

提示
为了使签名效果更加平滑,可以使用贝塞尔曲线(quadraticCurveTo 或 bezierCurveTo)来平滑曲线,但基本原理都是捕获触摸坐标,然后绘制曲线。


4. 附加功能:清除与保存

4.1 清除画布

通过调用 clearRect 方法可以清除整个 canvas 内容。

js
function clearCanvas() {
    // 清除整个 canvas
    this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
}

4.2 保存签名

使用 uni-app 提供的 API uni.canvasToTempFilePath 将 canvas 内容保存为图片文件,再传递给后续业务使用。

js
function saveSignature() {
    uni.canvasToTempFilePath(
        {
            canvasId: 'signature',
            // 传入 canvas 对象,保证获取正确内容
            canvas: this.ctx.canvas,
            fileType: 'png',
            quality: 1,
            success: (res) => {
                // 保存成功后,可将图片路径传递给父组件或进行其他处理
                console.log('保存成功,图片路径:', res.tempFilePath);
            },
            fail: (err) => {
                console.error('保存失败:', err);
            }
        },
        this
    );
}

注意
在调用 uni.canvasToTempFilePath 时,要确保 canvas 已经完全绘制好,且传入正确的 canvas 对象。