Canvas 签字板

预计阅读时间: 小于 1 分钟

场景需求:

需要开发一个移动端的手写板,要求是类似于签字版,于是就想到了使用 canvas 着手做一个满足业务需求。

本次实现的 canvas 签字版主要用于手机端网页,若用于 PC 端网页请自行对事件函数以及相应代码做对应的修改。

效果图:

  • 效果图-1 效果图-1
  • 效果图-2 效果图-2

实现代码:

基础样式
1* {
2	margin: 0;
3	padding: 0;
4}
5
6html {
7	overflow: hidden;
8	overflow-y: auto;
9}
10
11#app {
12	width: 100vw;
13	height: 100vh;
14	background-color: #ffffff;
15}
16
17/* 白板style */
18div.bb-center {
19	width: 100vw;
20	height: 100vh;
21	top: 0;
22	bottom: 0;
23	position: fixed;
24	background-color: rgba(0, 0, 0, 0.2);
25	z-index: 10;
26	font-size: 0.3rem;
27	visibility: hidden;
28}
29
30/* 显示画板 */
31div.bb-center.active {
32	visibility: visible;
33}
34
35.bbc-top {
36	box-sizing: border-box;
37	height: 0.8rem;
38	padding: 0.1rem 0.24rem;
39	width: 100%;
40	background-color: #fff;
41	display: flex;
42	justify-content: space-between;
43	align-items: center;
44}
45
46.bbc-top > div {
47	padding: 0.1rem 0.3rem;
48	font-size: 0.28rem;
49	color: #ffffff;
50	background: rgba(243, 125, 125, 1);
51	border-radius: 0.1rem;
52}
53
54.bbc-view {
55	width: 100vw;
56	height: calc(100vh - 0.8rem);
57}
58
59.bbc-view > canvas {
60	width: 100%;
61	height: 100%;
62}

html 页面布局使用的 rem 布局,根字体大小是 50px

页面布局
1<html>
2	<head></head>
3	<body>
4		<div id="app">
5			<div class="bb-center" :class="{active:isShow}">
6				<div class="bbc-top">
7					<div @click="closeBB">关闭</div>
8					<div @click="clearBB">清空</div>
9				</div>
10				<div class="bbc-view" ref="bbcView">
11					<canvas
12						ref="canvas"
13						:width="cvsWidth"
14						:height="cvsHeight"
15						@touchstart="onTouchStart"
16						@touchmove="onTouchMove"
17						@touchend="onTouchEnd"
18					></canvas>
19				</div>
20			</div>
21			<!-- 内容区 -->
22			<div class="wrap">
23				<button type="button" @click="openBB">打开画板</button>
24				<h3>canvas手写板</h3>
25			</div>
26		</div>
27	</body>
28</html>
逻辑代码
1const vm = new Vue({
2	el: "#app",
3	data: {
4		cvsWidth: 0,
5		cvsHeight: 0,
6		isShow: false,
7		ctx: "" // canvas对象
8	},
9	mounted() {
10		this.initCanvas();
11	},
12	methods: {
13		// 初始化canvas
14		initCanvas() {
15			let bbcView = this.$refs.bbcView;
16			// 设置canvas的宽度和高度
17			this.cvsWidth = bbcView.offsetWidth;
18			this.cvsHeight = bbcView.offsetHeight;
19
20			let $cvs = this.$refs.canvas;
21			if (!$cvs.getContext) return;
22			// canvas基础设置
23			this.ctx = $cvs.getContext("2d");
24			this.ctx.beginPath();
25		},
26		// 画布的触摸移动开始手势响应
27		onTouchStart(e) {
28			let offsetLeft = e.target.offsetLeft; // 获取canvas距离页面左边的距离
29			let offsetTop = e.target.offsetTop; // 获取canvas距离页面顶部的距离
30			let targetX = e.touches[0].clientX - offsetLeft;
31			let targetY = e.touches[0].clientY - offsetTop;
32			this.ctx.beginPath();
33			this.ctx.strokeStyle = "#000"; // 设置线条颜色
34			this.ctx.lineWidth = 3; // 设置线条的宽度
35			this.ctx.lineCap = "round"; // 设置线条的端点的样式,设为圆弧形
36			this.ctx.lineJoin = "round"; // 设置线条的连接点的样式,设为弧形
37			this.handleDraw(targetX, targetY);
38		},
39		// 画布的触摸移动手势响应
40		onTouchMove(e) {
41			let offsetLeft = e.target.offsetLeft; // 获取canvas距离页面左边的距离
42			let offsetTop = e.target.offsetTop; // 获取canvas距离页面顶部的距离
43			let targetX = e.touches[0].clientX - offsetLeft;
44			let targetY = e.touches[0].clientY - offsetTop;
45			this.handleDraw(targetX, targetY);
46		},
47		// 画布的触摸移动结束手势响应
48		onTouchEnd(e) {},
49		// 打开白板
50		openBB() {
51			this.isShow = true;
52			// this.ctx.clearRect(0, 0, this.cvsWidth, this.cvsHeight);
53			// // 重新设置canvas画板节点对象,否则绘画会出问题,这里异步操作,否则绘画有误
54			// setTimeout(() => {
55			// 	this.initCanvas();
56			// }, 100);
57		},
58		// 关闭白板
59		closeBB() {
60			this.isShow = false;
61		},
62		// 清空白板
63		clearBB() {
64			//清除画布
65			this.ctx.clearRect(0, 0, this.cvsWidth, this.cvsHeight);
66		},
67
68		// 绘制画笔
69		handleDraw(targetX, targetY) {
70			this.ctx.lineTo(targetX, targetY); // 将笔触移到当前点击点
71			this.ctx.stroke();
72		}
73	}
74});
TIP

注:本次使用的是基于 vue 开发的,若使用原生 JavaScript 开发,请自行对比修改。