uniapp实现手写签名,并在app中将其转为base64格式的图片
这里写自定义目录标题
- 1 手写签名页面:
- 2 封装canvas组件:
- 3 预览base64格式的签名图片:
uniapp实现手写签名,并在app中将其转为base64格式的图片
1 手写签名页面:
<template>
<!-- 手写签名-->
<!-- <view class="signatrueContent" @tap="startHui"> -->
<view class="signatrueContent">
<view class="title" @tap="cancel">取消</view>
<!-- <view class="title1" :class="{'isHui':!isShowTrue}" @tap="clearSign">
<image src="@/static/image/delectIco.png" alt="" />
<view>删除</view>
</view>
<view class="title2" @tap="confirmerSignature">确定</view> -->
<!-- <view v-if="!isShowTrue" class="title3">请在此处手写绘制签名</view> -->
<view class="signatrueMain" >
<!-- <view class="leftSignature" @tap="startHui"> -->
<view class="leftSignature">
<signature
canvasWidth="96%"
canvasHeight="96%"
ref="autograph"
></signature>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
showSign: true,
isShowTrue: false
}
},
methods: {
cancel(){
uni.navigateBack()
},
// startHui(){
// this.isShowTrue = true
// },
clearSign() {
// 清空
this.$refs.autograph.clearArea();
},
confirmerSignature() {
//把base64显示在签名处
let src = this.$refs.autograph.checkEmpty();
console.log(this.$refs.autograph)
console.log("最后===" + src)
//旋转图片
this.rotateBase64Img(src, -90, this.callback);
this.showSign = false;
// this.toggle = true
console.log('确定');
},
},
created() {
},
}
</script>
<style scoped lang="less">
.signatrueMain {
position: relative;
}
@media screen and (orientation: portrait) {
/*竖屏 css*/
.signatrueContent {
// padding: 40rpx 54rpx;
// width: 100vw;
height: 100vh;
position: relative;
background: #E8F3FF;
.title {
color: #111111;
font-weight: 600;
font-size: 32rpx;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-transform-origin: right center;
transform-origin: right center;
position: absolute;
right: 31px;
top: 50px;
z-index: 999999;
}
.title3 {
color: #111111;
font-size: 32rpx;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-transform-origin: right center;
transform-origin: right center;
position: absolute;
right: 50%;
text-align: center;
z-index: 9999;
top: 55%;
}
.title1 {
color: #111111;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-transform-origin: right center;
transform-origin: right center;
position: absolute;
left: -33rpx;
bottom: 50rpx;
display: flex;
align-items: center;
justify-content: center;
width: 158rpx;
height: 64rpx;
border-radius: 8rpx;
background: #1578FF;
font-size: 24rpx;
color: #fff;
z-index: 999;
image {
margin-right: 2px;
width: 24rpx;
height: 24rpx;
}
}
.title2 {
color: #111111;
font-size: 32rpx;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-transform-origin: right center;
transform-origin: right center;
position: absolute;
right: 31px;
color: #1578FF;
font-weight: 600;
z-index: 9999;
bottom: 28px;
}
.signatrueMain {
display: -ms-flexbox;
height: 100%;
width: 100%;
}
.buttonType {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
transform-origin: 40% 96%;
}
.leftSignature {
width: 100%;
height: 100%;
padding: 20rpx;
canvas {
width: 100%;
height: 100%;
transform-origin: 0% 0%;
}
}
.firstButton {
position: absolute;
bottom: 0;
right: 20px;
text {
color: #1578FF;
font-size: 32rpx;
}
}
.secondButton {
position: absolute;
top: 0;
right: 0;
text {
width: 316rpx;
height: 128rpx;
margin-top: 34rpx;
padding-top: 25rpx;
line-height: 50rpx;
img {
width: 48rpx;
height: 48rpx;
}
view {
font-size: 32rpx;
color: #1578FF;
}
}
}
canvas {
width: 30%;
height: 100%;
}
}
}
@media screen and (orientation: landscape) {
/*横屏 css*/
.signatrueContent {
padding: 20rpx 24rpx;
background: #E8F3FF;
.title {
color: #111111;
font-size: 18rpx;
}
.signatrueMain {
display: flex;
}
.leftSignature {
width: 100%;
height: 100%;
margin-right: 25rpx;
}
.firstButton {
button {
width: 64rpx;
height: 64rpx;
background: #EBF3FF;
border-radius: 8rpx;
img {
width: 24rpx;
height: 29rpx;
}
view {
font-size: 12rpx;
color: #333333;
}
}
}
.secondButton {
text {
margin-top: 34rpx;
width: 64rpx;
height: 64rpx;
background: #3171FF;
border-radius: 8rpx;
img {
width: 24rpx;
height: 24rpx;
}
view {
font-size: 12rpx;
color: #ffffff;
}
}
}
}
}
.isHui {
opacity: 0.5;
}
</style>
2 封装canvas组件:
<template>
<view class="main-content" v-if="isShow" @tap="startHui">
<!-- 签字canvas -->
<block v-if="showCanvas">
<canvas
class="mycanvas"
id="mycanvas"
canvas-id="mycanvas"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"
disable-scroll="true"
></canvas>
<!-- 旋转canvas -->
</block>
<block class="" v-else>
<image :src="imgurl" mode="" class="sign-img"></image>
</block>
<canvas
class="rotatCanvas"
id="rotatCanvas"
:style="{ 'z-index': -1, width: `${screenWidth}px`, height: `${(screenWidth * screenWidth) / screenHeight}px` }"
canvas-id="rotatCanvas"
></canvas>
<view class="title1" :class="{'isHui':!isShowTrue}" @tap="clear">
<image src="@/static/image/delectIco.png" alt="" />
<view>删除</view>
</view>
<view v-if="!isShowTrue" class="title3">请点击此处手写绘制签名</view>
<view class="title2" @tap="finish">确定</view>
<view class="mask" v-if="showModal" @tap.stop>
<view class="kw-modal flex align-items-center justify-content-center">
<view class="kw-modal-content">
<view class="flex justify-content-end font-size-34 lightgray">
<text class="iconfont icon-guanbi" @tap="close"></text>
</view>
<view class="flex justify-content-center font-size-38 font-600 kw-modal-title">
{{title}}
</view>
<view class="kw-modal-btnbox flex justify-content-between">
<view @tap="cancel" class="kw-modal-btn">{{cancelText}}</view>
<view @tap="confirm" class="kw-modal-btn">{{confirmText}}</view>
</view>
</view>
</view>
</view>
<view class="mask" v-if="showToast">
<view class="sign-toast flex align-items-center justify-content-center">
<view class="toast-box">请先签名</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
ctx: '', //绘图图像
points: [], //路径点集合
isShowTrue: false,
screenWidth: '',
screenHeight: '',
isRotatShow:false,
showModal:false,
showToast:false,
startX:'',
startY:'',
moveX:'',
moveY:'',
imgurl:'',
showCanvas:true,
title:'提示框',
cancelText:'取消',
confirmText:'确认',
base64Img: ''
};
},
props:{
isShow:{
type:Boolean,
default:true
}
},
mounted() {
this.createCanvas();
uni.getSystemInfo({
success: e => {
this.screenWidth = e.screenWidth;
this.screenHeight = e.screenHeight - 110;
console.log(e,'e')
}
});
},
methods: {
startHui(){
this.isShowTrue = true
},
show() {
this.clear();
this.isShow = true;
},
hide() {
this.$emit('close',false)
this.showCanvas = true
},
close(){
this.showCanvas = true
this.showModal = false
},
//取消保存
cancel(){
this.close()
//清除画布
this.clear()
},
confirm(){
this.rotat(this.base64Img);
},
save(){
this.showCanvas = false
console.log(this.moveX,'moveX')
console.log(this.moveY,'moveY')
// if(!this.moveX&&!this.moveY){
this.showToast = true
setTimeout(()=>{
this.showToast = false
this.showCanvas = true
},100)
// return false
// }
this.showModal = true
this.title = '确认签字?'
},
//创建并显示画布
createCanvas() {
this.showCanvas = true;
this.ctx = uni.createCanvasContext('mycanvas', this); //创建绘图对象
//设置画笔样式
this.ctx.lineWidth = 2;
this.ctx.lineCap = 'round';
this.ctx.lineJoin = 'round';
},
//触摸开始,获取到起点
touchstart(e) {
let startX = e.changedTouches[0].x;
let startY = e.changedTouches[0].y;
let startPoint = {
X: startX,
Y: startY
};
this.points.push(startPoint);
//每次触摸开始,开启新的路径
this.ctx.beginPath();
},
//触摸移动,获取到路径点
touchmove(e) {
this.moveX = e.changedTouches[0].x;
this.moveX = e.changedTouches[0].y;
let moveX = e.changedTouches[0].x;
let moveY = e.changedTouches[0].y;
let movePoint = {
X: moveX,
Y: moveY
};
this.points.push(movePoint); //存点
let len = this.points.length;
if (len >= 2) {
this.draw(); //绘制路径
}
},
// 触摸结束,将未绘制的点清空防止对后续路径产生干扰
touchend() {
this.points = [];
},
draw() {
let point1 = this.points[0];
let point2 = this.points[1];
this.points.shift();
this.ctx.moveTo(point1.X, point1.Y);
this.ctx.lineTo(point2.X, point2.Y);
this.ctx.stroke();
this.ctx.draw(true);
},
//清空画布
clear() {
this.ctx.clearRect(0, 0, this.screenWidth, this.screenHeight);
this.ctx.draw(true);
this.moveX = '';
this.moveY = '';
this.showCanvas = true
},
//完成绘画并保存到本地
finish() {
// console.log(this.moveX,this.moveY,11)
// if(!this.moveX && !this.moveY){
// uni.showToast({
// title: '请手写签名',
// icon: 'none'
// });
// return
// }
uni.canvasToTempFilePath(
{
canvasId: 'mycanvas',
success: res => {
this.imgurl = res.tempFilePath;
plus.io.resolveLocalFileSystemURL(res.tempFilePath, entry => {
entry.file(file => {
const fileReader = new plus.io.FileReader();
fileReader.onload = e => {
this.base64Img = e.target.result; // 保存 base64 编码的图片
this.save();
};
fileReader.readAsDataURL(file);
});
});
},
complete: com => {}
},
);
},
// 将图片选装
rotat(e) {
// this.isRotatShow = true
// this.showCanvas = true
let rotatCtx = uni.createCanvasContext('rotatCanvas', this); //创建绘图对象
// 重新定位中心点
rotatCtx.translate(0, (this.screenWidth * this.screenWidth) / this.screenHeight);
// rotatCtx.translate(0, 0);
// 将画布逆时针旋转90度
rotatCtx.rotate((270 * Math.PI) / 180);
// 将签字图片绘制进入Canvas
rotatCtx.drawImage(e, 0, 0, (this.screenWidth * this.screenWidth) / this.screenHeight, this.screenWidth);
// 保存后旋转后的结果
rotatCtx.draw(true);
setTimeout(() => {
// 生成图片并回调
uni.canvasToTempFilePath(
{
canvasId: 'rotatCanvas',
success: res => {
plus.io.resolveLocalFileSystemURL(res.tempFilePath, entry => {
entry.file(file => {
const fileReader = new plus.io.FileReader();
fileReader.onload = e => {
console.log('tempFilePath', e.target.result)
this.showCanvas = false
uni.setStorageSync('handleImgUrl',e.target.result)
console.log(e.target.result,'绘制的')
setTimeout(() => {
this.hide();
uni.navigateBack({
delta: 1
});
}, 100);
};
fileReader.readAsDataURL(file);
});
});
},
complete: com => {
// console.log(com);
}
},
this
);
}, 500);
}
}
};
</script>
<style lang="scss" scoped>
.title3 {
color: #111111;
font-size: 32rpx;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-transform-origin: right center;
transform-origin: right center;
position: absolute;
right: 50%;
text-align: center;
z-index: 9999;
top: 55%;
}
.title1 {
color: #111111;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-transform-origin: right center;
transform-origin: right center;
position: absolute;
left: -33rpx;
bottom: 50rpx;
display: flex;
align-items: center;
justify-content: center;
width: 158rpx;
height: 64rpx;
border-radius: 8rpx;
background: #1578FF;
font-size: 24rpx;
color: #fff;
z-index: 999;
image {
margin-right: 2px;
width: 24rpx;
height: 24rpx;
}
}
.title2 {
color: #111111;
font-size: 32rpx;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-transform-origin: right center;
transform-origin: right center;
position: absolute;
right: 31px;
color: #1578FF;
font-weight: 600;
z-index: 999;
bottom: 28px;
}
.main-content {
width: 100vw;
height: 100vh;
z-index: 9999;
overflow: hidden;
max-height:100vh;
}
.mycanvas {
width: 100vw;
height: 100%;
background-color: #E8F3FF;
position: fixed;
left: 0rpx;
top: 0rpx;
z-index: 2;
}
.sign-img{
width: 100vw;
height: 100vh;
}
.rotatCanvas{
background-color: red;
}
.button-line {
transform: rotate(90deg);
position: fixed;
bottom: -130rpx;
left: 260rpx;
align-items: center;
justify-content: space-between;
z-index: 999;
}
.button-style {
color: #ffffff;
width: 100px;
height: 120rpx;
text-align: center;
line-height: 120rpx;
border-radius: 10rpx;
margin-bottom: 40rpx;
font-size: 34rpx
}
.save-button {
@extend .button-style;
background-color: #02b340;
height: 140rpx;
line-height: 140rpx;
}
.clear-button {
@extend .button-style;
background-color: #ffa500;
height: 140rpx;
line-height: 140rpx;
}
.cancel-button {
@extend .button-style;
background-color: #e10b2b;
}
.mask{
width: 100vw;
height: 100vh;
background: rgba(0,0,0,0.8) ;
position: absolute;
top: 0;
left: 0;
z-index: 999;
}
.kw-modal,.sign-toast{
width: 50vw;
height: calc(100vh - 210px);
transform: rotate(90deg);
position: absolute;
top: 0;
left: -65rpx;
text-align: center;
z-index: 999;
}
.kw-modal-content{
width: 690rpx;
// height: 400rpx;
background: #efefef;
border-radius: 30rpx;
padding: 38rpx 30rpx 70rpx;
.kw-modal-title{
margin-top: 22rpx;
}
.kw-modal-tips{
margin-top: 20rpx;
}
.kw-modal-inp{
margin-top: 50rpx;
.kw-inp{
border: 1rpx solid #D9D9D9;
border-radius: 4rpx;
height: 70rpx;
line-height: 70rpx;
padding: 0 30rpx;
}
.inp-title{
margin-right: 20rpx;
}
}
.kw-modal-btnbox{
margin-top: 100rpx;
display: flex;
justify-content: space-around;
.kw-modal-btn{
width: 300rpx;
height: 84rpx;
background: #D9D9D9;
border-radius: 60rpx;
line-height: 84rpx;
text-align: center;
font-size: 30rpx;
&:last-child{
color: #FFFFFF;
background: #59A3FF;
}
}
}
}
.toast-box{
padding: 15rpx 30rpx;
// background-color: rgba(0, 0, 0, .7);
// color: #fff;
background-color: #ffffff;
color: #ffa500;
border-radius: 8rpx;
font-size: 30rpx;
}
</style>
3 预览base64格式的签名图片:
<view class="yzView">
<view class="yztext">印章预览</view>
<view class="isYzBox">
<image class="yzimg" mode="heightFix" :src="handleImg" alt="">
</view>
</view>
onShow(){
this.getSignet()
if(uni.getStorageSync('handleImgUrl')){
this.handleImg = uni.getStorageSync('handleImgUrl')
console.log(this.handleImg,'canvas')
}
}