目录
内容综述
画板项目搭建
画板实现
旧版接口
页面搭建
JavaScript文件
实现效果
新版接口
页面结构
JavaScript文件
实现效果
总结
本文主要阐述了我负责的微信小程序前端的项目搭建、画板结构的初步实现。
使用微信小程序的初衷,是PC端的Web需要使用鼠标操作,在描画时很难精确。所以,需要做一个在手机上实现的平台,便于画图。此外,这个平台是众包平台,所以必须尽可能不花费用户太大的动作,例如APP的下载就不可取。所以,不需要下载安装即可运行的微信小程序是最好的选择。
微信小程序比PC端的优点就是使用手指更加容易描画,所以画板是首要功能。我决定先搭建一个项目,完成基本的画板功能,之后再迁移到正式的项目源码中去。
在微信开发者工具,使用我微信账号的AppId创建一个新的Test1项目后,结构如下:
components存放组件;icon存放少量图标;pages存放页面;utils存放工具函数等;app.js是全局生命的JavaScript文件;app.json是全局配置文件;app.wxss是全局的样式文件。其余皆是一些配置文件,不需多说。
在pages目录,我创建了许多页面,以作代码的试错文件:
然后,我使用TabBar,将index、img、my、search这4个页面利用起来,作为画板的展示页面。在app.json中配置TabBar项:
这样,将会在小程序中展示这四个页面,TabBar效果如下:
在图片和搜索两个页面,我进行了画板的实现(Tab的名称与内容无关)。
画板需要借助canvas画布实现。之所以使用图片、搜索两个页面,是因为官方文档说明,微信小程序的canvas有新旧两套接口,而我之前一直使用的是旧版接口,新版接口较为陌生,可能实现起来比较慢。所以,我先在图片这一页实现旧版画布接口的画板,然后在搜索这一页实现新版画布接口的,最后观察其效果再行选择。
在官方文档中:
CanvasContext是旧版接口,也是我比较熟悉的接口,因此先采用它完成。
在img目录下的img.wxml中,搭建如下结构:
在总体的wrapper容器下,分为三个结构:canvas_wrapper是画布的容器,在里面放置画板;btn_wrapper是按钮容器,防止几个按钮;setView是弹窗结构。
在canvas_wrapper中,需要给画布设置背景图,使用户描图。因此,我使用绝对定位,让image标签作为背景图,置于canvas的层级下面;image的图片路径是动态指定的,为backgroundImgUrl。
在btn_wrapper中,设置如下代码:
它放置三个按钮,分别是橡皮画笔的转换、笔的粗细的设置、清空画板笔迹。
在setView中,设置如下代码:
它的作用是用户点击设置笔的按钮后,弹出设置的窗口。设置宽度,我使用slider组件,拖动控制条来指定宽度,下面放置确定和取消两个按钮。
最终,结合wxss文件,初步搭建的项目样式如下:
在JavaScript中,最关键的实现画布相关功能函数。
首先在data中准备需要的变量:
对于画布,封装一个函数,来初始化画布:
在这里,必须指定画布的id,在该id对应的容器内生成画布,并且设置画笔的性质。然后,在onLoad函数中调用它,以示在生命周期的加载期生成画布:
生成画布之后,若要能够描画, 还需给实现canvas标签绑定的touch和move事件函数:touchStart、touchMove。
在touchStart函数内部首先判断,如果用户刚刚点击了清空画布,那么画笔将要恢复默认配置,包括颜色、粗细、线头形状等。其中,我关注到一点,如果刚才用户刚刚修改了笔的粗细,那么才重新修改粗细为1。接着,修改当前的lineWidth为1,保证用户修改笔的粗细时显示此时线宽为1;hasClearCanvas为false,防止下次触摸时再次修改。最后,设置此次触摸的开始点坐标。
在touchMove函数中,首先确定了移动坐标,结合刚才的起始坐标,得到一条路径。再判断,如果是橡皮擦,则要清除该路径上的笔迹,否则是绘制新的路径。绘制结束后,设置新的起始坐标为当前的移动后坐标,便于下次移动。
这里提到了isClear变量,是标识当前是不是橡皮擦。在切换笔和橡皮的按钮中,它的回调函数调用了设置isClear的函数:
至此,画笔和橡皮都已经实现。然后需要实现清空画布函数:
清空画布后,需要修改data中的lineWidth、hasClearCanvas、hasSetPen,标志一切都重来。然后,框定一个完整的视口矩形,并且清空它。这样,等下次再触摸,在touchStart中就会设置画笔的配置。
接着,设置弹窗函数:
这里需要设置弹窗的显示标识ifShowSetView为true。然后需要注意的是,由于用户点开弹窗之后,在拖动滚动条后可能不会修改笔的宽度,因此只靠lineWidth记录当前笔的宽度就会丢失本来的粗细。所以,我设置了lineWidthBeforeChange,保留了最初的粗细。这样,在接下来,如果用户确定修改,则修改笔的宽度;否则,则把lineWidth重新赋为lineWidthBeforeChange,便于下次设置。
弹窗中的滑块slider用来设置笔的宽度,它绑定了函数:
此外,slider的value也绑定为lineWidth。所以,在用户看到slider时,slider的默认值就是当前笔的宽度。可见,用户拟修改的宽度,先保存在了lineWidth中。如果用户确定修改:
如果用户取消修改:
这样,就保证数据不会出错了。
在整个JavaScript逻辑中,需要着重考虑以下几个可能:
1、用户先设置笔的宽度,再描画
2、用户先清空,再描画
3、用户先清空,再设置,再描画
4、用户先设置,再清空,再描画
这其中比较难以注意的是:第4点,用户设置之后,如果先清空再描画,那么hasSetPen也会为false,因为一切重来了,所以在touchStart中会重新把笔的宽度设置为1;第3点,用户在清空之后,如果先设置再描画,这说明hasSetPen为true,因此在touchStart中就不会修改笔的宽度了。
这体现了程序的健壮性。
描画:
橡皮擦除:
设置笔的宽度:
清空:
实现效果较好,基本功能已经实现。
实现了旧版接口,新版接口的实现就容易许多了。由于旧版接口效果较好,所以我只简单实验了新版接口的效果,看看是否有较大提升。
在wxml文件中,构建如下代码:
结构与刚才很相似,不需多说,只是功能要简单些了。
在文件头部,获取当前设备的信息:
直接在onLoad函数中加载画布:
这段代码是参考自官方文档的示例。它的使用方法与旧版接口差异较大,但基本逻辑相同。
除了它,我简单实现了touchStart和touchMove方法:
在触感、延迟等方面,新版接口较旧版接口并没有明显提升。因此,我决定在正式源码中使用旧版接口。
在本文中,我总结了画板功能的初步实现,其中的难点在于画布相关功能实现和JavaScript逻辑。在接下来,我将搭建正式项目,包括实现登录接口等。