微信小程序电子签名组件,封装抽离可复用,签名成功输出base64和临时文件路径,解决vant弹窗中使用导致背景滚动问题,宽度自适应,高度设置百分比,开箱即用!
文章目录
一、效果图
。
二、组件完整代码示例
小程序根目录创建components文件夹,签名组件放在这个文件夹下,components文件夹下新建signature目录,
1.signature.js文件
代码如下(示例):
const app = getApp();
Component({
/**
* 组件的属性列表
*/
properties: {
//高度百分比
h: {
type: Number,
value: 0.2,
},
// 填充描述文字
fillText: {
type: String,
value: "请使用正楷",
},
},
/**
* 组件的初始数据
*/
data: {
canvas: "",
ctx: "",
pr: 0,
width: 0,
height: 0,
first: true,
},
attached: function () {
this.getSystemInfo();
this.createCanvas();
},
/**
* 组件的方法列表
*/
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;
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) {
_that.setData({
pr: res.pixelRatio,
width: res.windowWidth,
height: res.windowHeight * _that.data.h - 70,
});
},
});
},
//重签
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) => {
// 文件转base64
wx.getFileSystemManager().readFile({
filePath: res.tempFilePath,
encoding: "base64",
success: (val) => {
cb && cb(val,res);
// 转换成功派发事件
this.triggerEvent("success", val.data);
},
});
},
});
},
},
});
2.signature.wxml文件
代码如下(示例):
<view class="signature">
<canvas type="2d" id="canvas" bindtouchmove="move" bindtouchstart="start" binderror="error" style="width:{{width}}px;height:{{height}}px;">
</canvas>
</view>
3.signature.json文件
代码如下(示例):
{
"component": true,
"usingComponents": {}
}
4.signature.wxss文件
代码如下(示例):
.signature {
padding-top: 30px;
}
canvas {
background-color: white;
}
三、小程序页面引入组件使用示例,以index页面为例
1.index.wxml文件
本案例结合vant popup弹出框使用,可根据需求修改
代码如下(示例):
// 第一行解决弹窗签名时页面滚动问题
<page-meta page-style="{{ show ? 'overflow: hidden;' : '' }}" />
<view bindtap="test">测试签名</view>
<van-popup closeable show="{{ show }}" round position="bottom" custom-style="height: 50%" bind:close="onClose">
<view >
<signature h="{{0.5}}" class="signature" />
</view>
<view class="signature-btn">
<van-button type="primary" size="small" bindtap="reset">重置</van-button>
<van-button type="primary" size="small" bindtap="save">确认</van-button>
</view>
</van-popup>
2.index.js文件
代码如下(示例):
Page({
data: {
show:false,
},
test(){
this.setData({
show:true
})
},
// 保存
save(){
let signature = this.selectComponent('.signature');
signature.saveClick((res,url)=>{
// res:base64数据,url:临时文件url
console.log(res,url);
this.reset()
})
},
// 重置
reset(){
let signature = this.selectComponent('.signature');
signature.clearClick()
},
onClose(){
this.reset()
this.setData({
show:false
})
}
})
3.index.json文件
代码如下(示例):
{
"usingComponents": {
"signature": "../../components/signature/signature",
"van-popup": "@vant/weapp/popup/index"
},
"navigationBarTitleText":"页面标题",
"navigationBarTextStyle": "white",
}