效果图如下:
1.signature.js文件
var cxt = null;// 使用 wx.createContext 获取绘图上下文 cxt
var arrx = [];//所有点的X轴集合
var arry = [];//所有点的Y轴集合
var canvasw = 0;//画布的宽
var canvash = 0;//画布的高
// var canvasTop=0;
// var canvasLeft=0;
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
src:""
},
/**
* 组件的方法列表
*/
methods: {
//显示隐藏组件
back(){
//子组件传递给父组件一个方法canvasDis,并传递一个参数src给父组件
this.triggerEvent("canvasDis",{src:this.data.src})
},
//创建canvas上下文
createdCanvas(){
wx.showLoading({
title: '加载中...',
mask: true
})
// 使用 wx.createContext 获取绘图上下文 cxt
//创建 canvas 的绘图上下文,因为这里是封装成组件,所有需要加this
cxt = wx.createCanvasContext('canvas',this);
cxt.beginPath();
//封装成组件,所有需要in(this),如果不加无法创建画布
var query = wx.createSelectorQuery().in(this).select('.handCenter');
query.boundingClientRect(rect => {
// canvasTop = rect.top;
// canvasLeft = rect.left;
canvasw = rect.width;
canvash = rect.height;
wx.hideLoading()
}).exec();
},
//canvas发生错误时触发
canvasIdErrorCallback(e){
console.error(e.detail.errMsg)
},
//canvas触摸开始
canvasStart(e){
arrx.push(e.changedTouches[0].x);
arry.push(e.changedTouches[0].y);
},
//canvas触摸过程中
canvasMove(e){
let len = arrx.length;
cxt.moveTo(arrx[len - 1], arry[len - 1]);//把路径移动到画布中指定的点,第一个参数为x轴,第二个参数为y轴
arrx.push(e.changedTouches[0].x);//手指移动过程中canvas的横坐标存入到全局数组变量arrx中
arry.push(e.changedTouches[0].y);//手指移动过程中canvas的纵坐标存入到全局数组变量arry中
cxt.lineTo(e.changedTouches[0].x, e.changedTouches[0].y);//moveTo坐标到lineTo坐标的
cxt.setLineWidth(4);//设置线条的宽度
cxt.setLineCap('round');//设置结束时 点的样式
cxt.stroke();//画线
cxt.draw(true);//设置为true时,会保留上一次画出的图像,false则会清空(方式二设置为false,一为true)
},
getimg() {
if (arrx.length == 0) {
wx.showModal({
title: '提示',
content: '签名内容不能为空!',
showCancel: false
});
return false;
};
wx.showLoading({
title: '签名生成中..',
mask:true
})
let that = this;
wx.canvasToTempFilePath({
canvasId: 'canvas',
success: function (res) {
that.setData({
src: res.tempFilePath
})
wx.hideLoading();
//子组件传递给父组件一个方法canvasDis,并传递一个参数src给父组件
that.triggerEvent("canvasDis",{src:res.tempFilePath})
}
},this)
},
cleardraw() {
//清除画布
arrx = [];
arry = [];
cxt.clearRect(0, 0, canvasw, canvash);
cxt.draw();
this.setData({src:''});
},
canvasEnd(e){}
},
ready(){
this.createdCanvas()
}
})
2.signature.wxml文件
<view>
<view class="signCont">
<label class="signTitle">请在下方空白处签名</label>
</view>
<view class="handBtn">
<!-- <button catchtap="cleardraw" class="delBtn">清空</button>
<button catchtap="getimg" class="subBtn">完成</button> -->
<van-button round catchtap="cleardraw">重签</van-button>
<van-button round type="info" catchtap='getimg'>签名确认</van-button>
</view>
<view class="wrapper">
<view class="handCenter">
<canvas class="canvas"
id="canvas"
canvas-id="canvas"
disable-scroll="true"
bindtouchstart="canvasStart"
bindtouchmove="canvasMove"
binderror="canvasIdErrorCallback"></canvas>
<cover-image class='overImg' src="{{src}}" wx:if="{{src!=''}}"></cover-image>
</view>
</view>
</view>
3.signature.json
{
"component": true,
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
}
4.sginature.wxss文件
.wrapper{
position: fixed;
top:0;
bottom: 0;
right: 0;
left: 0;
box-sizing: border-box;
background-color: #fff;
}
.back{
width: 160rpx;
background: #008ef6;
margin: 20rpx;
padding: 10rpx 0;
color:#fff;
border-radius:16rpx;
text-align: center;
}
.handCenter{
box-sizing: border-box;
width: 100%;
}
canvas {
width:100%;
height: 800rpx;
margin:auto;
}
.overImg{
width: 200rpx;
height: 200rpx;
}
.handCenter {
box-sizing: border-box;
}
.handBtn {
position: fixed;
bottom: 20rpx;
right: 20rpx;
width: 100%;
display: flex;
justify-content: flex-end;
z-index: 99;
}
.handBtn button{
width: 120rpx;
height: 36px;
}
.handBtn van-button {
margin-right: 14rpx;
}
.delBtn {
color: #666;
}
.subBtn {
background: #008ef6;
color: #fff;
}
button{
font-size: 24rpx;
}
.signCont {
height: 300rpx;
display: flex;
align-items: center;
}
.signTitle {
position: fixed;
top: 0;
left: 20rpx;
width: 100%;
z-index: 1;
color: #666;
font-size: 12px;
}
二、小程序页面引入组件使用示例 .wxml文件
<view>
<signature bindcanvasDis="handlChangeCanvasShow"></signature>
</view>
.json文件
"usingComponents": {
"signature": "../../../components/signature/signature",
"van-button": "@vant/weapp/button/index"
},
"pageOrientation": "landscape", // 横屏展示
"navigationBarTitleText":"签字",
"navigationBarTextStyle": "white"
.js文件
const app = getApp();
const util = require('../../../utils/util')
Page({
/**
* 页面的初始数据
*/
data: {
signBase64: '',
taskId: null,
prevType: null,
agencySignUrl: '',
supervisorSignUrl: '',
comptrollerSignUrl: '',
can:false,
src:"",
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.setData({
taskId: options.id,
prevType: options.type
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
},
uploadBase64(signBase) {
let that = this
app.http.wxaxios({
url: '/wechat/common/upload/base64',
method: 'POST',
data: {
url: signBase
},
success: function(res){
if(res.data.code === 200) {
let resInfo = res.data.data
that.confirmSign()
} else {
wx.showToast({
title: res.data.message,
icon: 'error',
duration: 2000
})
}
wx.hideLoading()
},
fail:function(res){
wx.hideLoading()
wx.showToast({
title: res.data.message,
duration: 2000
})
}
})
},
confirmSign() {
let that = this
app.http.wxaxios({
url: '/wechat/auditTask/confirm', // 后台给的上传接口
method: 'POST',
data: {}, // 参数
success: function(res){
if(res.data.code === 200) {
} else {
wx.showToast({
title: res.data.message,
icon: 'error',
duration: 2000
})
}
wx.hideLoading()
},
fail:function(res){
wx.hideLoading()
wx.showToast({
title: res.data.message,
duration: 2000
})
}
})
},
//handlChangeCanvasShow自定义事件,子组件传递过来的方法和数据
handlChangeCanvasShow(e){
let that = this
let tempFilePath = e.detail.src
wx.getFileSystemManager().readFile({
filePath: tempFilePath,
encoding: "base64",
success: (val) => {
that.uploadBase64('data:image/jpeg;base64,'+val.data)
},
})
}
})