记录一下项目中遇到的问题
需求是h5有个签名板,当用户签完名后需要把签名照片上传给后端
第一步:实现签名版功能--返回base64格式图片
<template>
<view>
<view class="sign-content">
<view>
<view class="reset" @click="backClick" style="position:fixed;bottom: 466rpx;background:#fff;">返回</view>
<view class="reset" @click="clearClick" style="position:fixed;bottom: 266rpx;background:#fff;">重写</view>
<view class="reset" @click="saveClick" style="position:fixed;bottom: 66rpx;background: #39b54a;color:#fff;">确定
</view>
</view>
<canvas class="sign" canvas-id="sign" @touchmove="move" @touchstart="start" @touchend="end" @touchcancel="cancel"
@longtap="tap" disable-scroll="true" @error="error"></canvas>
<view>
<view style="transform: rotate(90deg);text-align: center;position:fixed;width:130rpx;right:-14rpx;top:46%;">签名板
</view>
</view>
</view>
</view>
</template>
<script>
let content = null;
let touchs = [];
export default {
data() {
return {
isMove: false,
createCanvas: false,
outW: 0,
outH: 0,
windowsH: 0,
windowsW: 0
};
},
onLoad: function(options) {
//获得Canvas的上下文
content = uni.createCanvasContext('sign');
this.windowsH = uni.getSystemInfoSync().windowHeight;
this.windowsW = uni.getSystemInfoSync().windowWidth;
//设置线的颜色
content.setStrokeStyle('#000000');
//设置线的宽度
content.setLineWidth(5);
//设置线两端端点样式更加圆润
content.setLineCap('round');
//设置两条线连接处更加圆润
content.setLineJoin('round');
// content.setFillStyle('white')
// content.fillRect(0, 0, 750, 700)
// content.draw()
},
methods: {
backClick: function() {
uni.navigateBack({
delta: 1
});
},
// 画布的触摸移动开始手势响应
start: function(event) {
// console.log("触摸开始" + event.changedTouches[0].x);
// console.log("触摸开始" + event.changedTouches[0].y);
//获取触摸开始的 x,y
let point = {
x: event.changedTouches[0].x,
y: event.changedTouches[0].y
};
touchs.push(point);
},
// 画布的触摸移动手势响应
move: function(e) {
let point = {
x: e.touches[0].x,
y: e.touches[0].y
};
touchs.push(point);
if (touchs.length >= 2) {
this.isMove = true;
this.draw(touchs);
}
},
// 画布的触摸移动结束手势响应
end: function(e) {
console.log('触摸结束' + e);
//清空轨迹数组
for (let i = 0; i < touchs.length; i++) {
touchs.pop();
}
},
// 画布的触摸取消响应
cancel: function(e) {
console.log('触摸取消' + e);
},
// 画布的长按手势响应
tap: function(e) {
console.log('长按手势' + e);
},
error: function(e) {
console.log('画布触摸错误' + e);
},
//绘制
draw: function(touchs) {
let point1 = touchs[0];
let point2 = touchs[1];
touchs.shift();
content.moveTo(point1.x, point1.y);
content.lineTo(point2.x, point2.y);
content.stroke();
content.draw(true);
},
//清除操作
clearClick: function() {
//清除画布
content.clearRect(0, 0, this.windowsW, this.windowsH);
content.draw(true);
this.isMove = false;
},
//保存图片
saveClick: function() {
if (this.isMove == false) {
uni.showToast({
icon: 'none',
title: '请绘制签名'
})
return
}
var that = this;
uni.showLoading({
title: '请稍等'
});
uni.canvasToTempFilePath({
canvasId: 'sign',
success: function(res) {
uni.getImageInfo({
src: res.tempFilePath,
fail() {
uni.hideLoading();
uni.showToast({
title: '获取图片信息失败'
});
},
success: function(image) {
//要先设置在获取 ,加载问题
image.height = parseInt(image.height);
image.width = parseInt(image.width);
that.outW = image.width;
that.outH = image.height;
//修复大屏手机无法生成图片问题
let maxWidth = that.windowsW - uni.upx2px(240);
let base = that.outH / that.outW;
if (that.outH > maxWidth) {
that.outH = maxWidth;
that.outW = Math.floor(that.outH / base);
}
content.rotate(-Math.PI / 2);
content.translate(-that.outW, 0);
content.drawImage(image.path, 0, 0, that.outW, that.outH);
content.translate(that.outW, 0);
content.rotate(Math.PI / 2);
content.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: 'sign',
fileType: 'jpg',
width: that.outH,
height: that.outW,
sdestWidth: image.height,
sdestHeight: image.width,
fail(res) {
uni.hideLoading();
uni.showToast({
title: '签名失败',
icon: 'none'
});
},
success: function(resss) {
uni.hideLoading();
that.clearClick()
uni.$emit('sign', resss
.tempFilePath); /* resss.tempFilePath返回的是base64格式的图片 */
uni.navigateBack();
// let imgArr = [];
// imgArr.push(resss.tempFilePath);
// uni.previewImage({
// urls: imgArr,
// success(response) {
// console.log(response);
// }
// });
}
});
});
}
});
},
fail() {
uni.hideLoading();
}
});
}
}
};
</script>
<style lang="scss" scoped>
.sign-content {
display: flex;
height: 100vh;
background: #f1f1f1;
/* #ifdef H5 */
// height: calc(100vh - 44px);
/* #endif */
padding: 20rpx 0;
box-sizing: border-box;
.reset {
background-color: rgb(248, 248, 248);
border: 1px solid #ddd;
transform: rotate(90deg);
margin-top: 20rpx;
padding: 20rpx 40rpx;
font-size: 28rpx;
border-radius: 28rpx;
border: none;
}
.tips {
width: 600rpx;
color: red;
transform: rotate(90deg);
height: 10px;
position: fixed;
left: -233rpx;
top: 326rpx;
/* #ifdef H5 */
top: calc(326rpx + 88rpx);
/* #endif */
font-size: 34rpx;
}
.sign {
flex: 1;
height: 100%;
margin-right: 100rpx;
margin-left: 120rpx;
border: 1px dashed #ddd;
background-color: #fff;
}
}
.g-btns {
text-align: center;
margin-top: 1rem;
transform: rotate(90deg);
-ms-transform: rotate(90deg);
/* IE 9 */
-moz-transform: rotate(90deg);
/* Firefox */
-webkit-transform: rotate(90deg);
/* Safari 和 Chrome */
-o-transform: rotate(90deg);
position: absolute;
top: 12rem;
left: -6rem;
}
.g-btns {
width: 7.5rem;
height: 2.25rem;
font-size: 0.9rem;
font-weight: bold;
border: none;
border-radius: 1rem;
}
.u-reset {
background: #ddd;
color: #666;
margin-right: 0.5rem;
}
.u-submit {
background: #fc4949;
color: #fff;
margin-left: 0.5rem;
}
</style>
第二步:上传图片(分为base64上传和文件流上传)
上传图片需要后端配合,如果后端给的接口是可以上传base64的直接调用即可,如果后端给的是二进制上传接口,就需要前端把base64转为文件在调用接口,这里主要记录base64转文件
1,base64转文件
//base64编码的图片
let timestamp = new Date().getTime();
let sunumber = Math.floor(Math.random() * 999);
var file = this.base64ToFile(this.base64, timestamp + sunumber)
//base64转flie
base64ToFile(base64, name = "file") {/* base64这个字段是你需要转换的base64图片 */
if (typeof base64 != 'string') {
return;
}
var arr = base64.split(',')
var type = arr[0].match(/:(.*?);/)[1]
var fileExt = type.split('/')[1]
var bstr = atob(arr[1])
var n = bstr.length
var u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], `${name}.` + fileExt, {
type: type
})
},
如果是在h5上需要多一步,h5会把base64渲染为_doc/uniapp_temp_.png的格式
Uniapp使用Canvas绘制签名画布时,浏览器内向后端发送签名图片时为Base64,真机上自动转为_doc/uniapp_temp_.png的格式,解决方法如下
https://blog.csdn.net/X1379305656/article/details/129399794
uni.$on('sign', (data) => {
// 转换为base64
pathToBase64(data)
.then(base64 => {
this.base64 = base64
this.upload()
// this.input()
})
.catch(error => {
console.error(error)
})
})
这里使用的是uniapp插件转换为base64
https://ext.dcloud.net.cn/plugin?id=123
2.调用接口
由于使用的是uniapp,所以直接调用uni.uploadFile()方法
upload(){
uni.uploadFile({
url: this.baseUrl + "",这里放地址
name: 'file',
file: file,这个是转换好的二进制文件
fileType: 'image',
formData: {
'user': 'test' // 上传附带参数
},
success: (uploadFileRes) => {
const res = JSON.parse(uploadFileRes.data)
if (res.code == 200) {
console.log(res.data.url, "图片上传成功");
this.signatureFlow(res.data.url)
}
},
fail: (res) => {
console.log('上传失败', res)
},
})
}
本人的第一篇博客,谢谢大家,写的不好的地方欢迎指正