uniapp 使用canvas实现签字功能(兼容h5,app,小程序)
前言
一套代码实现兼容性,主要的区别在于拿到图片地址之后,如何转成base64给后端。
提示:以下是本篇文章正文内容,下面案例可供参考
html
<template>
<view class="signa">
<view class="btn">
<view class="hand-title">手写签名</view>
<view @click="clear" class="rewrite-btn">重写</view>
<view @click="save" class="save-btn">使用</view>
</view>
<view class="canvas-wrap">
<canvas class="canvas" disable-scroll="true" canvas-id="canvasId" @touchstart="starts" @touchmove="moves" @touchend="end"></canvas>
</view>
<Message ref="Message"></Message>
</view>
</template>
css
根据自己的需求调整样式和html,主要代码在js上
<style scoped lang="scss">
.signa {
position: relative;
overflow: hidden;
height: 100vh;
width: 100vw;
z-index: 1;
.canvas-wrap {
display: flex;
justify-content: center;
align-items: center;
width: calc(100vw - 180rpx);
height: 100vh;
}
.canvas {
width: 100%;
height: 100vh;
background-color: #f4f8fb;
position: absolute;
z-index: 9999;
}
.btn {
width: 160rpx;
right: 0;
position: fixed;
font-size: 40rpx;
.cancel-btn {
position: fixed;
top: 30rpx;
right: 0;
color: $uni-text-color-blue;
transform: rotate(90deg);
}
.hand-title {
position: fixed;
top: 45%;
right: -40rpx;
transform: rotate(90deg);
}
.rewrite-btn {
position: fixed;
top: 80%;
right: 0;
color: #666666;
font-size: 36rpx;
transform: rotate(90deg);
}
.save-btn {
position: fixed;
bottom: 60rpx;
right: -10rpx;
padding: 0 10rpx;
color: #fff;
background: #f43e3c;
border-radius: 7rpx;
transform: rotate(90deg);
font-size: 36rpx;
}
}
}
</style>
js
使用 // #ifdef MP-WEIXIN || APP-PLUS|| H5 // #endif 来实现当前处于哪个端,走什么方法
<script>
/*
* 已兼容h5,小程序端,app端
*/
import boboMessage from "@/landlord/signContract/components/bobo-message/bobo-message.vue";
export default {
data() {
return {
dom: null,
line: [],
radius: 0,
isMove: false,
main: {
},
pdfURl: '',
showCanvas: false,
ctx: '', //绘图图像
points: [], //路径点集合
signature: '',
content: '',
base64: '',
sureForm: {
} //上一页带过来的数据
};
},
components: {
Message: boboMessage,
},
created() {
this.dom = uni.createCanvasContext("canvasId", this);
},
onLoad: function(options) {
//接收上一页的数据
let item = JSON.parse(options.tranform)
this.sureForm = item
},
methods: {
end(e) {
},
distance(a, b) {
let x = b.x - a.x;
let y = b.y - a.y;
return Math.sqrt(x * x + y * y);
},
starts(e) {
this.line.push({
points: [{
time: new Date().getTime(),
x: e.touches[0].x,
y: e.touches[0].y,
dis: 0,
}, ],
});
let currentPoint = {
x: e.touches[0].x,
y: e.touches[0].y,
};
this.currentPoint = currentPoint;
this.drawer(this.line[this.line.length - 1]);
},
moves(e) {
this.isMove = true;
let point = {
x: e.touches[0].x,
y: e.touches[0].y,
};
(this.lastPoint = this.currentPoint), (this.currentPoint = point);
this.line[this.line.length - 1].points.push({
time: new Date().getTime(),
x: e.touches[0].x,
y: e.touches[0].y,
dis: this.distance(this.currentPoint, this.lastPoint),
});
this.drawer(this.line[this.line.length - 1]);
},
drawer(item) {
let x1,
x2,
y1,
y2,
len,
radius,
r,
cx,
cy,
t = 0.5,
x,
y;
var time = 0;
if (item.points.length > 2) {
let lines = item.points[item.points.length - 3];
let line = item.points[item.points.length - 2];
let end = item.points[item.points.length - 1];
x = line.x;
y = line.y;
x1 = lines.x;
y1 = lines.y;
x2 = end.x;
y2 = end.y;
var dis = 0;
time = line.time - lines.time + (end.time - line.time);
dis = line.dis + lines.dis + end.dis;
var dom = this.dom;
var or = Math.min(
(time / dis) * this.linePressure + this.lineMin,
this.lineMax
);
cx =
(x - Math.pow(1 - t, 2) * x1 - Math.pow(t, 2) * x2) /
(2 * t * (1 - t));
cy =
(y - Math.pow(1 - t, 2) * y1 - Math.pow(t, 2) * y2) /
(2 * t * (1 - t));
dom.setLineCap("round");
dom.beginPath();
dom.setStrokeStyle("black");
dom.setLineWidth(5);
dom.moveTo(x1, y1);
dom.quadraticCurveTo(cx, cy, x2, y2);
dom.stroke();
dom.draw(true);
}
},
clear() {
this.dom.clearRect(0, 0, 1000, 1000);
this.dom.draw();
this.isMove = false;
},
// 以上方法可拿去直接用,接下来是重点
save() {
uni.showLoading({
title: "加载中",
mask: true
});
if (!this.isMove) return this.$refs.Message.error("尚未进行签名!");
// 小程序拿到图片转base64方法
// #ifdef MP-WEIXIN
uni.canvasToTempFilePath({
canvasId: "canvasId",
fileType: 'png',
quality: 1, //图片质量
success: (res) => {
var baseAddress;
uni.getFileSystemManager().readFile({
filePath: res.tempFilePath, //选择图片返回的相对路径
encoding: 'base64', //编码格式
success: res => {
// 成功的回调
this.baseAddress = 'data:image/jpeg;base64,' + res.data
// ... 后端接口的地方
}
})
}
});
// #endif
// h5的方法
// #ifdef H5
uni.canvasToTempFilePath({
canvasId: "canvasId",
fileType: 'png',
quality: 1, //图片质量
success: (res) => {
var baseAddress;
uni.request({
url: res.tempFilePath,
method:'GET',
responseType:'arraybuffer',
success: ress => {
// 成功的回调
this.baseAddress = 'data:image/jpeg;base64,' + uni.arrayBufferToBase64(ress.data)
// ... 后端接口的地方
}
})
}
});
// #endif
// app的方法
// #ifdef APP-PLUS
uni.canvasToTempFilePath({
canvasId: 'canvasId',
success: function(res) {
var path = res.tempFilePath;
var base64;
return new Promise((resolve, reject) => {
plus.io.resolveLocalFileSystemURL(path, function(entry) {
entry.file(function(file) {
var AppReader = new plus.io.FileReader();
AppReader.onloadend = function(e) {
that.base64 = e.target.result
// 拿到bade64调接口
that.saveForm(that.base64)
resolve(base64.split(",")[1])
};
AppReader.onerror = function(err) {
reject(err)
};
AppReader.readAsDataURL(file);
}, function(e) {
reject(e)
});
});
})
}
})
// #endif
},
// #ifdef APP-PLUS
saveForm(val) {
let params = {
}
*****(params).then(req => {
if (req.data.code == 0) {
this.$u.toast(req.data.message)
uni.navigateBack({
delta:2
})
} else {
this.$u.toast(res.data.message);
}
})
}
// #endif
}
};
</script>
效果如下: