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

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

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

无数据:

手写以后

实现步骤,及代码

  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
}
相关推荐
yangzhi_emo32 分钟前
ES6笔记5
前端·笔记·es6
Hexene...1 小时前
【前端Vue】el-dialog关闭后黑色遮罩依然存在如何解决?
前端·javascript·vue.js·elementui·前端框架
Jay_See1 小时前
JC链客云——项目过程中获得的知识、遇到的问题及解决
前端·javascript·vue.js
普通码农2 小时前
Element Plus 数字输入框箭头隐藏方案
前端
草字2 小时前
css flex布局,设置flex-wrap:wrap换行后,如何保证子节点被内容撑高后,每一行的子节点高度一致。
前端·javascript·css
Slice_cy2 小时前
深入剖析Vue框架:实现精简的computed
前端
局i2 小时前
ES6 类与继承:现代 JavaScript 面向对象编程
前端·javascript·es6
白菜上路2 小时前
C# Web API Mapster基本使用
前端·c#
叫我詹躲躲2 小时前
偷偷收藏!前端老鸟绝不外传的150个JS插件,让你效率翻3倍…
前端·vue.js
会豪2 小时前
如何让自己的前端项目更优雅
前端