1、签名组件(思路是使用canvas 转换成base64图片 返给后端 之后 获取的时候 后端再把当前存储的 路径返回)
const app = getApp();
Component({
/**
* 组件的属性列表
*/
properties: {
// 高度百分比
h: {
type: Number,
value: 0.2,
},
// 填充描述文字
fillText: {
type: String,
value: "请使用正楷",
},
},
/**
* 组件的初始数据
*/
data: {
canvas: "",
ctx: "",
pr: 0,
width: '',
height: '',
first: true,
},
attached: function () {
this.getSystemInfo();
this.createCanvas();
},
ready() {
},
/**
* 组件的方法列表
*/
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;
console.log(res[0],'res[0]')
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) {
console.log(res,'getSystemInfo')
_that.setData({
pr: res.pixelRatio,
width: res.windowWidth,
height: res.windowHeight * _that.data.h ,
});
},
});
},
//重签
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) => {
cb && cb(res);
// // 转换成功派发事件
this.triggerEvent("success", res);
// 如果需要使用base64的可以使用下面的,此处只用临时路径,注释掉这个功能
// 文件转base64
// wx.getFileSystemManager().readFile({
// filePath: res.tempFilePath,
// encoding: "base64",
// success: (val) => {
// cb && cb(val,res);
// // 转换成功派发事件
// this.triggerEvent("success", val.data);
// },
// });
},
});
},
},
});
<view class="signatureView">
<canvas type="2d" id="canvas" bindtouchmove="move" bindtouchstart="start" binderror="error" style="width:{{width}}px;height:{{height}}px;"
force-use-old-canvas="true">
</canvas>
</view>
saveSignature(){
let _this=this;
let signature = this.selectComponent('.signature');
signature.saveClick((result)=>{
//图片上传
wx.showLoading({
title: '上传中...',
onLoad: true,
mask: true
})
wx.uploadFile({
url: app.data.upfileDomainName,
filePath:result.tempFilePath,
name: 'file',
formData: {},
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + wx.getStorageSync('access_token')
},
success(res) {
var dataInfo = JSON.parse(res.data);
if (res.statusCode == 200 && dataInfo.status*1===200) {
_this.setData({
['audit.signatureFilePath']:dataInfo.data[0].fileNewName,
previewPath:dataInfo.data[0].url,
})
_this.onCloseSignature()
} else {
_this._Toast('上传失败');
}
wx.hideLoading({noConflict: true})
},
fail(err) {
console.log(err, '图片上传失败')
wx.hideLoading({noConflict: true})
_this._Toast('上传失败');
}
})
})
},
2、完整代码
//这个是 编写的时候
<van-field
label="签名"
readonly
required
title-width="100%"
border="{{ false }}"
/>
<view class="bg-white padding15">
<view class="ww-flex flex-col col-ct row-ct" style="background: #F7F8FA;height:140px" data-qmuser="ywclqm" bindtap="openSignature">
<image wx:if="{{!audit.signatureFilePath}}" src="./img/icon_qm.png" style="width:36px;height:36px"></image>
<view wx:if="{{!audit.signatureFilePath}}" style="padding-top:5px;color:#4E5969">点此签名</view>
<image wx:if="{{audit.signatureFilePath}}" src="{{previewPathName}}{{previewPath}}" style="width:100%;height:140px"></image>
</view>
</view>
//编写打开弹窗
<van-popup closeable show="{{ show }}" position="bottom" z-index="35" custom-style="width:100%;height: 50%" bind:close="onCloseSignature">
<view class="WH ww-flex flex-col" wx:if="{{show}}">
<view class="flex1">
<signature h="{{0.4}}" class="signature" /> //组件
</view>
<view class="flex-none ww-flex flex-row paddingLR15">
<view class="flex1 textCenter signatureBtn marginR20" bindtap="resetSignature">重置</view>
<view class="flex1 textCenter signatureBtn" bindtap="saveSignature">确认</view>
</view>
</view>
</van-popup>
3.组件内容(画布)
<view class="signatureView">
<canvas type="2d" id="canvas" bindtouchmove="move" bindtouchstart="start" binderror="error" style="width:{{width}}px;height:{{height}}px;"
force-use-old-canvas="true">
</canvas>
</view>
4、画布js
const app = getApp();
Component({
/**
* 组件的属性列表
*/
properties: {
// 高度百分比
h: {
type: Number,
value: 0.2,
},
// 填充描述文字
fillText: {
type: String,
value: "请使用正楷",
},
},
/**
* 组件的初始数据
*/
data: {
canvas: "",
ctx: "",
pr: 0,
width: '',
height: '',
first: true,
},
attached: function () {
this.getSystemInfo();
this.createCanvas();
},
ready() {
},
/**
* 组件的方法列表
*/
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;
console.log(res[0],'res[0]')
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) {
console.log(res,'getSystemInfo')
_that.setData({
pr: res.pixelRatio,
width: res.windowWidth,
height: res.windowHeight * _that.data.h ,
});
},
});
},
//重签
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) => {
cb && cb(res);
// // 转换成功派发事件
this.triggerEvent("success", res);
// 如果需要使用base64的可以使用下面的,此处只用临时路径,注释掉这个功能
// 文件转base64
// wx.getFileSystemManager().readFile({
// filePath: res.tempFilePath,
// encoding: "base64",
// success: (val) => {
// cb && cb(val,res);
// // 转换成功派发事件
// this.triggerEvent("success", val.data);
// },
// });
},
});
},
},
});