需要开发一个移动端的手写板,要求是类似于签字版,于是就想到了使用 canvas 着手做一个满足业务需求。
本次实现的 canvas 签字版主要用于手机端网页,若用于 PC 端网页请自行对事件函数以及相应代码做对应的修改。
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});
注:本次使用的是基于 vue 开发的,若使用原生 JavaScript 开发,请自行对比修改。