小程序开发指北

之前自己做了一个类似驾考宝典的小程序 叫通达驾考。这篇博客主要就是想记录一下开发中遇到的一些坑和小程序中使用的有趣的技术。

前言

首先这篇文章并不是小程序的入门文章而且小程序开发相对简单。所以在阅读这篇文章的时候需要一定的前端基础和对类Vue的小程序有一定的了解(现在又了mpVue来开发小程序了!)。

其次小程序在微信的平台下获取的巨大的流量所推动的经济与变革还是值得让每一位开发者去认真的去对待这个新鲜的事物。

进阶

这个项目落地的时候距离上一次自己写小程序的项目已经过去了半年了,小程序在这半年中经历了长足的成长,不仅原生的支持了Component组件的写法。而且有了behaviors来解决组件之间的通讯。

抽象节点与插件的出现极大的丰富了小程序的世界,不仅可以使用优秀开发者开源的公共插件来提升产品迭代的速度,也丰富了小程序的社区与开源精神。

项目

已经说了足够多的闲聊了,下面来将下在这个项目中遇到的一些坑和踩坑的学习之路。

回答后的翻页

这个标题的表述可能有点小的直白,但在项目中遇到的问题确实在这次的开发中使得收获颇丰。

首先参考了一下市面上成熟的项目,因为是答题类型的产品,存在一个点就是在用户完成一次答题的点击之后需要跳转到下一题或者展示正确的答案的情况下是否需要页面间的跳转。

简单的来说一开始看到这个项目的时候因为答题有一个类似纸质书的翻页的效果,所以第一直觉想到的应该是一个类似轮播翻页的一个效果那么实现在项目中可能就是完成一次答题之后页面做一次跳转。

但是后来决定直接在页面上做一个数据的替换来代替这个效果,因为要做真是的跳转的话会出现各种意外的bug与页面之间数据携带的高度耦合。这个在开发中完全是可以通过更换实现的方式来避免画蛇添足的。

在确定了实现翻页的效果是替换数据之后又进入了一个更大的坑中…因为那段时间一直在看阮一峰的《ES6入门》一书,其中的Generator function的暂停执行让我觉得可以应用在项目中实现答题之后切换数据的情况。

还行当时及时止住,替换为了使用对象存放键值对来做数据的替换

1
2
3
4
5
this.setData({
topic: array, // 请求的全部题目
current: res.data.data[0], // 当前的题目
'current.answerList': list // 用户回答的数组
})

这个小的改动不仅使我在处理后面的上一题的开发与用户在模拟考试中对已经回答过的问题做修改的时候避免了无穷无尽的填坑。而且使用一个对象来保存当前的题目相对于在一个数组中切换currentNumber来得更浅显易懂。

另外整个项目做题正误的判断都是在前端来进行判断的。所以在处理各种用户在使用中产生的边界情况也让我认识到了一个项目代码的健壮性对一个程序的开发与迭代需求的重要性。

确定了技术选型之后就是实现了,在这个方案的实现中遇到了一些小的坑主要是前端展示的题目存在不同的类型,比如单选题与多选题的区别。就不能用单一的方式去判断是否符合正确的答案了。

另外在翻页中需要额外注意的就是防抖的问题了,用户快速的点击以及在最后一题的时候的判断的情况。此处仅为当时考虑不周实际并无太大难度就不细说了。

小程序中的组件

因为在开发的时候小程序已经原生支持了Components的使用,所以在处理可复用的组件的时候就毫不犹豫的使用了小程序的Components。因为网上对Components与小程序的文档的介绍都是不很清楚,所以在这就着重的说下。

首先小程序的Component的使用:

在小程序中注册组件与页面稍有不同,首先需要在该组件的Json文件中声明该文件是一个组件

1
2
3
{
"component": true
}

wxml文件与wxss文件与其他的页面并无太大的区别,主要是在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
Component({

behaviors: [],

properties: {
myProperty: { // 属性名
type: Array, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
value: '', // 属性初始值(可选),如果未指定则会根据类型选择一个
observer: function (newVal, oldVal) {
} // 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:'_propertyChange'
},
myProperty2: String // 简化的定义方式
},
data: { // 私有数据,可用于模版渲染
},
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function () {
},
moved: function () { },
detached: function () { },

methods: {

_myPrivateMethod: function () {
// 内部方法建议以下划线开头
this.replaceDataOnPath(['A', 0, 'B'], 'myPrivateData') // 这里将 data.A[0].B 设为 'myPrivateData'
this.applyDataUpdates()
},
_propertyChange: function (newVal, oldVal) {

}
}

})

首先看起来也是大部分的内容都是还算明了比如并无差异的data,但是仔细一看却又是有非常大的不同在其中的。首先出现了一个methods的方法,这个了解Vue的同学一定是并不觉得陌生直接在methos中声明和使用方法就可以了。

其次生命周期与普通的小程序的页面便有了很大的不同,不在有onLoad等生命周期了反而出现的是attached、moved、detached这三个生命周期,在Component中这三个生命周期分别代表加载的时候,被移除的时候,和被删除的时候。

接下来再来看properties, 在小程序的Component中也可以像在Vue中使用组件一样的在组件上直接传入属性,在组件内接收父组件传递过来的值。

组件之间的通讯

在使用Components之后怎么向他的父组件进行通讯如何传递参数和事件。

在与父组件通讯的情况下可以调用父组件已经注册的方法来实现。首先在组件上直接绑定事件

1
<组件名 bind:changeChoose="changeSelectTab"></组件名>

然后在组件上可以使用triggerEvent触发事件

1
this.triggerEvent('changeChoose', eventDetail, eventOption)

总结

本篇文章介绍了在开发小程序的时候遇到的一些坑和其中的一些解决的方案。在baidu + google的帮助下还是顺利的解决了曾经一度让我怀疑人生的问题。

前端的进阶路上更多的是不懈的踩坑与进步~

hi you can see me