h5手写签名

雄小勤H5项目最近需要实现H5手写签名效果,项目是uniapp框架,uniapp本身没有手写签名组件,经过调研可以用H5属性canvas实现。

一、html部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<view class="container">
<view class="sign-box">
<canvas
class="mycanvas"
canvas-id="mycanvas"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"
></canvas>
</view>
<view class="sigh-btns">
<u-button text="重写" @tap="handleReset"></u-button>
<u-button color="#2589EF" type="primary" text="确认" @tap="handleConfirm"></u-button>
</view>
</view>

* touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发。
* touchmove事件:当手指在屏幕上滑动的时候连续地触发。
* touchend事件:当手指从屏幕上离开的时候触发。

二、js部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import {chooseFilePromise, uploadFilePromise} from "@/util/request/upload.js"
import {api, urlApi,} from '@/util/request/api.js'
var tempPoint = []; //用来存放当前画纸上的轨迹点,用来判断当前是否签名了
export default {
data() {
return {
ctx: '', //绘图图像
points: [], //路径点集合
uri: ''
};
},
mounted() {
document.getElementsByTagName("body")[0].style.overflowY = "hidden"
this.ctx = uni.createCanvasContext("mycanvas", this); //创建绘图对象
//设置画笔样式
this.ctx.lineWidth = 4;
this.ctx.lineCap = "round"
this.ctx.lineJoin = "round"
},
methods: {
//触摸开始,获取到起点
touchstart: function(e) {
let startX = e.changedTouches[0].x;
let startY = e.changedTouches[0].y;
let startPoint = {
X: startX,
Y: startY
};

/* **************************************************
#由于uni对canvas的实现有所不同,这里需要把起点存起来
* **************************************************/
this.points.push(startPoint);
//每次触摸开始,开启新的路径
this.ctx.beginPath();
},
//触摸移动,获取到路径点
touchmove: function(e) {
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(); //绘制路径
}
tempPoint.push(movePoint);
},
// 触摸结束,将未绘制的点清空防止对后续路径产生干扰
touchend: function() {
this.points = [];
},
/* ***********************************************
# 绘制笔迹
# 1.为保证笔迹实时显示,必须在移动的同时绘制笔迹
# 2.为保证笔迹连续,每次从路径集合中区两个点作为起点(moveTo)和终点(lineTo)
# 3.将上一次的终点作为下一次绘制的起点(即清除第一个点)
************************************************ */
draw: function() {
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)

},
// handleCancel(){
// uni.navigateBack({
// delta: 1
// });
// },
//清空画布
handleReset: function() {
let that = this
uni.getSystemInfo({
success: function(res) {
let canvasw = res.windowWidth;
let canvash = res.windowHeight;
that.ctx.clearRect(0, 0, canvasw, canvash);
that.ctx.draw(true);
},
})
tempPoint = [];
},
//将签名笔迹存到本地
handleConfirm: function() {
let that = this
if (tempPoint.length == 0) {
uni.showToast({
title: '请先签名',
icon: 'none',
duration: 2000
});
return;
}
uni.canvasToTempFilePath({
canvasId: 'mycanvas',
success: function(res) {
// const tempPath = res.tempFilePath;
// console.log(res, '00000')

const options = {
tempFilePath: res.tempFilePath,
tempFile: new Date().getTime() + '.png',
url: urlApi + api.commonUpload
}
uni.showLoading()
uploadFilePromise(options).then(ret => {
console.log(ret,'88888')
that.handleReset()
that.$emit('submit', ret.url)

uni.hideLoading()
uni.showToast({
title: '上传成功',
duration: 2000,
icon: 'none'
});
}).catch(e => {
uni.hideLoading()
})
// this.uri = tempPath
//这里主要是根据实际需求要将笔迹旋转一定角度,再保存下来
// uni.compressImage({
// src: tempPath,
// quality: 100,
// rotate:270,
// success: function(result) {

// }
// })
}
})
}
},
destroyed() {
document.getElementsByTagName("body")[0].style.overflowY = ""
}
};
  • lineCap 属性:设置或返回线条末端线帽的样式。(square为正方形)
  • lineJoin 属性:设置或返回所创建边角的类型,当两条线交汇时。(bevel:斜角、miter尖角)
  • beginPath() 方法:开始一条路径,或重置当前的路径。
  • moveTo():把路径移动到画布中的指定点,不创建线条
  • lineTo():添加一个新点,然后在画布中创建从该点到最后指定点的线条
  • stroke():绘制已定义的路径
  • Draw():用于将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中
  • clearRect()方法:清空给定矩形内的指定像素。

三、css部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 .container {
// display: flex;
// flex-direction: row;
height: 100%;
overflow: hidden;
padding: 32rpx 0;
}

.sign-box {
width: 90%;
height: 70%;
margin: auto;
}

.sign-view {
height: 100%;
}

.sigh-btns {
// height: 100%;
margin: auto;
display: flex;
// flex-direction: column;
justify-content: space-around;
padding: 16rpx;
margin-top: 20rpx;
.u-button{
margin: 0 40rpx;
}
}

.btn {
margin: auto;
padding: 8rpx;
// transform: rotate(90deg);
border: grey 1rpx solid;
}

.mycanvas {
height: 100%;
width: 100%;
background-color: #ECECEC;
}