微信小程序封装一个手写签名组件

今年入职了一家公司做前端,专门写微信小程序,现在开发告一段落,也终于有空总结一下开发过程中遇到的问题和一些收获,今天分享一个手写签名的组件实现方法。

先看效果,实现了一个横屏的手写签名组件

无数据:

手写以后

实现步骤,及代码

  1. 第一步 创建一个 signature 文件

  2. 第二步 创建四个文件名称分别为,index.js、index.json、index.wxml、index.wxss

  3. 第三步 在index.json中声明 "component": true

使用

1、在父组件的json中引入组件 并且将 pageOrientation 设置为 true 否则不会横屏

json 复制代码
{
  "usingComponents": {
    "signature": "/components/signature/index"
  },
  "pageOrientation": "landscape"
}

2、父组件的html中直接引入就好

xml 复制代码
<view>
    <signature></signature>
</view>

代码部分

index.wxml

html 复制代码
    <view class="modal-content-area">
        <view class="modal-content">
            <view class="toast" wx:if="{{!hasDraw}}">
                请工整地写出自己的姓名~
            </view>
            <canvas canvas-id="signature" class="modal-canvas" disable-scroll="{{true}}" id="handWriting" bindtouchstart="scaleStart" bindtouchmove="scaleMove" bindtouchend="scaleEnd"></canvas>
            <view class="modal-bottom">
                <view class="clear_signature" bindtap="">
                </view>
                <view class="flex_btn">
                    <view class="modal-btn modal-clear" bindtap="clearCanvas">清除</view>
                    <view class="modal-btn modal-confirm" bindtap="save">确认</view>
                </view>
            </view>
        </view>
    </view>
</view>

index.wxss

css 复制代码
.signature-modal {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    z-index: 3;
    background: blue;
}

.modal-mask {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: 4;
    background-color: rgba(0, 0, 0, .5);
}

.modal-content-area {
    z-index: 5;
    width: 100%;
    height: 100%;
    background: #F5F7FB;
    position: absolute;
}

.modal-content {
    width: 100%;
    height: 100%;
    background: #ffffff;
}

.modal-canvas {
    width: 100vw;
    height: 83vh;
    background: #F5F7FB !important;
    border: 1rpx solid rgba(0, 0, 0, 0.08);
    border-radius: 4rpx;
    z-index: 1;
}


.modal-bottom {
    position: absolute;
    bottom: 15rpx;
    display: flex;
    align-items: center;
    justify-content: space-between;
    z-index: 100;
    width: 100vw;
    box-sizing: border-box;
    padding: 0 32rpx;
}

.modal-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 85rpx;
    height: 30rpx;
    background: rgba(103, 149, 255, 0.2);
}

.modal-clear {
    font-size: 13rpx;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #3670F5;
    margin-right: 12rpx;
}

.modal-confirm {
    background: #3670F5;
    font-size: 13rpx;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #FFFFFF;
}

.modal-btn:nth-child(1) {
    border-right: 1rpx solid #ffffff;
}

.clear_signature {
    /* position: absolute; */
    top: 40rpx;
    right: 15rpx;
    display: flex;
    align-items: center;
    z-index: 1;
    font-size: 13rpx;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #3670F5;
    /* background-color: #F5F7FB; */
    z-index: 100;
}

.clear_signature>text {
    height: 17rpx;
}

.clear_signature>image {
    width: 15rpx;
    height: 15rpx;
    margin-right: 2rpx;
}

.toast {
    position: absolute;
    top: 40%;
    left: 42%;
    transform: rotate(-50%, -50%);
    z-index: 100;
    font-size: 13rpx;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: rgba(58, 65, 85, 0.4);
}

.flex_btn {
    display: flex;
    align-items: center;
}

index.js

js 复制代码
Component({
    /**
     * 组件的初始数据
     */
    data: {
        tempFilePath: '',
        hideModal: false,
        hasDraw: false,
        canvasName: '#handWriting',
        ctx: '',
        canvasWidth: 0,
        canvasHeight: 0,
        startPoint: {
            x: 0,
            y: 0,
        },
        selectColor: 'black',
        lineColor: '#1A1A1A', // 颜色
        lineSize: 1, // 笔记倍数
        radius: 5, //画圆的半径
    },
    // 初始化画布
    ready() {
        this.setData({
            hideModal: false
        })
        let that = this
        let query = wx.createSelectorQuery().in(this);
        //获取自定义组件的SelectQuery对象
        this.canvasCtx = wx.createCanvasContext('signature', that)
        // 设置线的样式
        this.canvasCtx.setLineCap("round");
        this.canvasCtx.setLineJoin("round");
        // 初始化颜色
        this.canvasCtx.setStrokeStyle(that.data.selectColor);
        // 初始化粗细
        query.select('.modal-canvas').boundingClientRect(rect => {
            this.setData({
                canvasWidth: rect.width,
                canvasHeight: rect.height,
            });
        }).exec();
    },
    // 方法列表
    methods: {
        scaleStart(event) {
            if (event.type != 'touchstart') return false;
            let currentPoint = {
                x: event.touches[0].x,
                y: event.touches[0].y
            }
            // this.data.ctx.moveTo(currentPoint.x, currentPoint.y)
            this.drawCircle(currentPoint);
            this.setData({
                startPoint: currentPoint,
                hasDraw: true, //签字了
            });
        },
        mouseDown() {},
        scaleEnd(e) {
            this.setData({
                isStart: true
            })
        },
        scaleMove(event) {
            if (event.type != "touchmove") return false;
            let {
                startPoint
            } = this.data
            let currentPoint = {
                x: event.touches[0].x,
                y: event.touches[0].y
            }

            this.drawLine(startPoint, currentPoint)
            this.setData({
                startPoint: currentPoint
            })
        },
        drawCircle(point) { //这里负责点
            let ctx = this.canvasCtx;
            ctx.beginPath();
            ctx.setFillStyle(this.data.lineColor)
            //笔迹粗细由圆的大小决定
            ctx.arc(point.x, point.y, this.data.radius, 0, 2 * Math.PI);
            ctx.fill();
            ctx.closePath();
            ctx.draw(true)
        },
        drawLine(sourcePoint, targetPoint) {
            let ctx = this.canvasCtx;
            this.drawCircle(targetPoint);
            ctx.beginPath();
            ctx.setStrokeStyle(this.data.lineColor)
            ctx.setLineWidth(this.data.radius * 2)
            ctx.moveTo(sourcePoint.x, sourcePoint.y);
            ctx.lineTo(targetPoint.x, targetPoint.y);
            ctx.stroke();
            ctx.closePath();
        },
        clearCanvas() {
            //清空画布
            let ctx = this.canvasCtx;
            ctx.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeight);
            ctx.fillStyle = 'rgba(0, 0, 0, .1)';
            ctx.draw()
            this.setData({
                hasDraw: false //未签字
            })
        },
        save() {
            let {
                hasDraw,
            } = this.data
            if (!hasDraw) {
                wx.showToast({
                    title: '还未签字哟!',
                    icon: 'none',
                    mask: true
                })
                return
            } else {
                this.saveToImage();
            }
        },
        saveToImage() {
            let that = this;
            let {
                canvasHeight,
                canvasWidth
            } = that.data;
            wx.canvasToTempFilePath({
                x: 0,
                y: 0,
                width: canvasWidth,
                height: canvasHeight,
                canvasId: 'signature',
                success(res) {
                    console.log(res.tempFilePath, "res.tempFilePath");
                    if (res.tempFilePath) {
                        that.setData({
                            tempFilePath: res.tempFilePath
                        })
                    }
                },
                fail(err) {
                    console.log(err);
                }
            }, that)
        }
    }
})

index.json

json 复制代码
{
    "usingComponents": {},
    "component": true
}
相关推荐
海的诗篇_26 分钟前
前端开发面试题总结-vue2框架篇(四)
前端·css·面试·vue·html
用户4266705916926 分钟前
为什么说不可信的Wi-Fi不要随便连接?
前端
玺同学1 小时前
从卡顿到流畅:前端渲染性能深度解析与实战指南
前端·javascript·性能优化
光影少年1 小时前
vuex中的辅助函数怎样使用
前端·javascript
teeeeeeemo1 小时前
JS数据类型检测方法总结
开发语言·前端·javascript·笔记
木木黄木木1 小时前
HTML5 火焰字体效果教程
前端·html·html5
云墨-款哥的博客1 小时前
失业学习-前端工程化-webpack基础
前端·学习·webpack
MAOX7891 小时前
基于python的web系统界面登录
前端·python
懒大王、1 小时前
Vue添加图片作为水印
前端·javascript·vue.js
Junerver1 小时前
如何在Jetpack Compose中轻松的进行表单验证
前端·kotlin