书名:微信小程序开发入门精要
ISBN:978-7-115-45245-0
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
• 编 著 李 宁
责任编辑 张 涛
责任编辑 张 爽
• 人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
• 读者服务热线:(010)81055410
反盗版热线:(010)81055315
本书系统全面、循序渐进地介绍了进行微信小程序开发的各方面知识、经验和技巧。本书内容包含目前微信小程序支持的所有组件和API的详细介绍,以及使用方法演示,并附有大量的实例代码。除此之外,还增加了一些高级UI技术的介绍,例如WeUI、wx-charts等,这些高级UI技术会使开发工作事半功倍。本书的最后提供了完整的微信小程序项目案例,可以让读者在全面深入地了解了微信小程序开发的知识和技巧后,达到学以致用的目的。
本书内容通俗易懂,深入浅出,是微信小程序初学者的入门首选,也是微信小程序开发者的进阶必备!
我虽然在微信公众号、Android、iOS方面有多年的开发经验,对这些系统非常了解,也写过多本关于Android技术的书,但还是第一次专门写与微信相关的技术书。微信小程序于2017年1月9日正式上线发布,但到目前为止,开发工具和系统库仍然在不断更新中。本书从开始写作到正式出版,与小程序相关的技术可能已经被更新多次了,因此,我在写作本书时,要时刻关注与小程序相关的技术和工具的最新进展,以保证本书在出版时能够使用较新的微信小程序IDE和开发库。这与写作Android和iOS的书有很大的不同,Android和iOS通常是要一年进行一次大的更新,而微信小程序的更新频率可能是一周或更短。如果读者在拿到本书时发现微信小程序已经有了更新的版本,一定程度上并不影响本书的阅读,因为微信小程序的升级会尽量保持向下兼容。但可能有少部分的代码会出现问题,读者可通过“源码下载和技术交流”处的二维码进入微信公众号提问,或到我的个人博客http://geekori.cn中提问及得到最新的源程序。
由于微信活跃用户已经超过7亿,因此腾讯在微信上推出的产品都会被庞大的用户群体所关注,尤其是可能成为一种颠覆技术的微信小程序。尽管微信小程序未提供独立入口,但这并不影响大家对微信小程序的关注。
因为微信小程序在技术上与微信公众号有着本质的不同,前者是基于本地组件的,后者实质是在手机上运行的Web程序,所以在性能和用户体验方面,微信小程序更具优势。虽然现在可使用的微信小程序数量仍然远没有微信公众号多,但这只是暂时的。当广大企业和程序员发现微信小程序的潜力后,以及随着新型的开发工具问世,会有各种类型的微信小程序大量涌现,到时再学习微信小程序的开发,恐怕就赶不上第一拨红利了。因此,现在正是学习它的最好时机。
尽管微信小程序的主要开发语言是JavaScript,但由于其UI(wxml文件)需要依赖类似于CSS的样式(wxss)设计,而且wxss和CSS非常相似,几乎可以互相替代,因此,对CSS的掌握程度在很大程度上决定了是否能设计出更绚丽的微信小程序。所以,和微信公众号一样,要想进入微信小程序开发领域,就要对CSS有一定的了解。由于本书的主题是微信小程序,所以并不会对CSS有深入的讲解。如果读者感觉阅读样式文件(wxss)有些困难,建议先阅读一些CSS入门类的书籍,这样对阅读本书会起到事半功倍的效果。
开发微信小程序必备的两种技术是JavaScript和CSS,如果你对这两种技术都有一些了解,那么可以尽情阅读本书的内容!本书会让你对程序开发模式有一个全新的认识。如果你对这两种技术不太熟悉也没有关系,因为JavaScript和CSS都非常简单易学,可以一边查找学习资料,一边学习,也会非常快的,这时谷歌或百度就会成为你最好的老师,你也可以通过微信公众号与我探讨相关的技术。现在就让我们进入微信小程序的开发殿堂吧!
本书内容通俗易懂,由浅入深,既适合初学者,也同样适合专业人员。学习本书之前,要拥有一个微信账号,除此之外,需要有一定的编程基础,最好会一点JavaScript和CSS。
阅读本书时,你可以根据自身的情况来决定如何阅读。如果你是初学者,对微信小程序完全不了解,建议从第1章开始阅读,这样会很容易理解本书的内容。如果你已经阅读过其他相关文章,对微信小程序有一定的了解,那么可以从本书选取任何你感兴趣的内容阅读。温馨提醒,很多章节都有大量的精彩代码和经验总结,千万不要错过!
本书全面系统地介绍了微信小程序各方面的开发技术,并提供了大量的精彩代码和案例。全书主要内容如下。
微信小程序入门,包括第1~第2章,主要介绍了什么是微信小程序,微信小程序开发环境的配置和布局,并开发了本书的第一个微信小程序(从开发到发布的全过程演示)。
组件,包括第3~第8章,主要介绍了微信小程序目前支持的原生组件,通过这些组件以及样式的配合,可以设计出千变万化的微信小程序。
API,包括第9~第15章,主要介绍了微信小程序目前支持的原生API,包括网络、多媒体、数据存取、位置、设备、界面等内容。
WeUI,包括第16~第17章,介绍了微信官方推出的一套基础样式库,利用这套基础样式库,可以很容易地设计出炫酷的微信小程序UI。
项目实战,包括第18~第21章,给出了3个微信小程序项目,以及一个wx-charts图表样式库的应用。通过学习这些项目,读者可以掌握开发一款完整的微信小程序的一般步骤。开发微信小程序并不需要完全从零开始,目前已经有很多开源库可以使用,例如wx-charts,这些开源库可以让开发工作事半功倍。
本书的源代码、勘误和最新内容的更新都将通过微信公众号提供,读者既可以扫描下面的二维码进入微信公众号,也可以加入本书作者的技术交流QQ群(264268059)探讨微信小程序的开发技术。
作者
微信小程序是腾讯在2016年9月推出的一种新型的微信扩展。尽管目前还没有正式开发,但依然受到了非常多的关注。这主要是由于腾讯的影响力,以及微信在国内拥有的庞大的用户群体。在2017年1月9日,腾讯已经正式上线了小程序,这意味着任何人都可以在手机微信中使用小程序。由于目前小程序的数量还不多,所以现在进入小程序开发领域,可能会赶上小程序的第一拨红利。OK,废话少说,从本章开始,让我们深入了解微信小程序的原理以及详细的开发过程。
微信小程序刚一公布,朋友圈就被微信小程序刷爆了!“微信之父”张小龙说:“小程序是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用。这也体现了‘用完即走’的理念,用户不关心是否安装太多应用的问题。应用将无处不在,随时可用,但又无需安装卸载”。
我也看了网上的一些关于微信小程序的文章,但内容质量良莠不齐。好吧,我就通过本节让大家了解一下什么是微信小程序,以及微信小程序到底能为我们带来什么。
由于之前有微信公众号,而公众号里面的程序其实就是将移动Web(主要是HTML5、CSS、JavaScript等技术)嵌入到微信中,当然,会调用一些微信提供的API。所以很多人自然而然会想到微信小程序用的也是HTML5。但事实是,微信小程序和HTML5,甚至和Web,没有任何关系。因为Web的性能低下,尤其对于那些追求完美的人,在手机上使用Web简直不能忍受。千万别说,等以后手机性能发展到和现在的PC一样就好了,估计等到那时候,会出现比手机更小巧,当然,性能也更差的设备。如果手机成为了PC,那么这些新出现的设备将会取代现在手机的位置。就像人们永远等待新产品降价再买,但等到这些产品真降价了,又会有更好的产品问世,很难等到既享受新产品,同时又享受低价的时候。
既然说微信小程序和Web一点关系都没有,那么有什么证据呢?这一点从微信小程序官方文档的描述中就可以看出。感兴趣的读者可以通过下面的地址查看微信小程序官方文档。
https://mp.weixin.qq.com/debug/wxadoc/dev/
微信小程序主要由3个全局的文件和一些与页面有关的文件组成,全局文件包括app.js、app.json和app.wxss。其中,app.js是JavaScript文件,用于编写全局的事件,例如微信小程序启动时要执行的代码,类似于iOS工程中AppDelegate.m文件的作用;app.json用于配置微信小程序,例如由哪些页面组成,类似于Android工程中AndroidManifest.xml文件的作用;app.wxss是公共样式表,用于设置整个工程都可以使用的样式,类似于Android中的theme或style资源,全局都可以使用。
可能有人会问,微信小程序不是使用了JavaScript吗?难道和Web没有关系?这里需要明确,JavaScript只是一种语言,未必用在Web上,JavaScript同样可以用在服务端,如Node.js,当然也可以用在移动端,作为独立的语言运行。
微信小程序的页面部分由4个文件组成,这里的页面实际上就是窗口。假设页面名字为index,那么该页面由index.js、index.wxml、index.wxss和index.json组成。index.js用于编写页面的逻辑代码;index.wxml是腾讯自己设计的一种标记语言,可以称为微信标记语言,用于描述UI;index.wxss是针对该页面的样式表,是私有的;index.json是针对页面的配置文件。
这里关键点是index.wxss,用过React Native的读者应该很熟悉JSX,它是一种描述UI的类XML语言。其基本原理是通过XML文件描述UI,并动态创建原生的UI。例如,React Native用View来描述顶层视图,用Text来描述文本输出控件,那么我们可以使用下面的代码来模拟这一动态创建过程。
Android:
View component = null;
if(tag == "View")
{
component = new ViewGroup(…);
}
else if(tag == "Text")
{
component = new TextView(…);
}
iOS:
UIView *component;
if(tag == "View")
{
component = [UIView new];
}
else if(tag == "Text")
{
component = [UILabel new];
}
上面描述的是基本的动态创建组件的过程,当然,实际的实现过程要比这个复杂得多,这里只做了原理上的描述。很显然,系统会根据不同平台,以及在JSX中的描述,生成不同的原生组件。
React Native使用的是JSX,类似地,微信小程序使用的是wxml(微信标记语言),它是一种腾讯自己设计的类JSX的语言,下面是wxml的代码示例。
<view class="container">
<view bindtap="bindViewTap" class="userinfo">
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
下面则是JSX的代码示例。
<View style={{flex:1}}>
<DrawerLayoutAndroid
ref={drawerLayoutAndroid => { this.drawerLayoutAndroid = drawerLayoutAndroid; }} drawerWidth={150}
drawerPosition={DrawerLayoutAndroid.positions.left}
renderNavigationView={() =>navigationView}>
<View style={{flex: 1, alignItems:'center'}}>
<Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>我是主布局内容</Text>
</View>
</DrawerLayoutAndroid>
<View style={{flexDirection:'row'}}>
<Text style={{flex:1}} onPress={this.onPress.bind(this)}>Open</Text>
<Text style={{flex:1}}
onPress={()=>this.drawerLayoutAndroid.closeDrawer(0)}>Close</Text>
</View>
</View>
从上述的两段代码可以看出,JSX和wxml非常相似,只是具体的组件名称和命名风格不同。例如,JSX所有组件名称首字母都大写(例如Text),而wxml所有组件名称首字母都小写(例如text),此外,组件属性也有一定的差异。
不管JSX和wxml的代码风格是否一样,系统处理它们的原理都是一样的,即根据这些代码自动生成原生的组件,就像前面描述的动态创建原生组件的过程一样。
尽管小程序本身和HTML5无关,但“微信Web开发者工具”(开发小程序的IDE)本身却和HTML5有很大的关系。开发“微信Web开发者工具”的技术是NW.js(node-webkit),这是一种允许使用HTML5、CSS和JavaScript开发跨平台(Windows、Mac OS X和Linux)桌面应用的框架,和NW.js类似的框架是Electron(Github主导的开源项目),用Electron开发的著名项目包括Atom IDE、Visual Studio Code、WordPress等。也就是说,不管是NW.js,还是Electron,都足够强大,以至于可以开发IDE和很多系统软件。尽管这两个框架都使用了HTML5作为UI描述,但在PC上,HTML5的性能表现良好(毕竟PC的CPU足够强大)。如果读者对使用Web技术开发跨平台桌面应用感兴趣,可以关注我的博客(http://geekori.cn),我会不定期推出相关的技术文章。
尽管本书的主题是微信小程序,但这里还要提一下原生热布局的概念。由于目前移动平台主要有Android和iOS,但这两个平台使用的开发技术完全不同(前者主要使用Java,后者主要使用OC或Swift),所以就需要有一种可以同时开发两种平台的技术,这样理论上可以节省一半的开发成本。
以前比较流行的技术是混合开发(Hybird),这种技术很简单,就是HTML5+CSS+JavaScript的结合。和木桶原理一样,木桶装多少水,是由最短那个木板决定的,而在这三者组合中,HTML5就成为那个短板,降低了Hybird的整体性能。
对于Hybird技术,我们只需要其中的两个优势:跨平台和热更新。跨平台很好理解,各个平台都会有Web浏览器,而热更新主要是逻辑代码和UI布局的热更新。在逻辑代码方面,热更新用JavaScript,这里主要讨论UI布局的热更新。在Hybird时代,使用的是HTML5和CSS,它们进行热更新没问题,但性能有问题。如果把HTML5组件和原生的组件放到同一个窗口,就可以感觉到它们的不同。所以现在的主要焦点在于UI布局可以实现热更新,性能达到或接近原生组件。HTML5达到了前者的要求,但没有达到后者的要求。我们知道,Android布局使用了Layout,iOS布局使用了storyboard,不管是哪种技术,都不支持热更新,都是固化到apk和ipa文件中的。不过这两种技术都支持动态创建组件,所以React Native率先推出了利用JSX描述组件的位置、尺寸以及其他属性,然后再根据这些属性动态创建本地组件的技术。JSX会生成一种中间状态,我们可以称为虚拟DOM(Virtual DOM),其实就是一种中间组件而已,然后系统会根据运行平台的不同(Android或iOS),将其动态生成不同平台的原生组件,这样很容易实现热更新。因为JSX就是个普通的文本文件,可以很容易地从网络上下载,这一点和HTML5相同。由于组件都是动态创建原生的,所以和在Layout、storyboard中定义的静态原生组件的性能相同,因此,很容易解决前面描述的问题。我们也可以把这种利用XML或其他格式描述UI布局,并实现动态生成原生组件的技术称为原生热布局。
微信小程序借鉴了React Native的原理。不同的是,React Native是通用的,而且可以随意扩展。而微信小程序必须运行在微信提供的架构上,是一种寄生的原生热布局。
除了React Native和微信小程序,还有阿里巴巴的Weex,这是阿里巴巴前端团队发布的一个开源框架,有兴趣的读者可以到http://alibaba.github.io/weex这个地址研究这些框架。也是用了类似Virtual DOM的技术,可以三位一体(Android/iOS/HTML5),React Native对应的React.js可以生产HTML5,微信小程序理论上也可以。希望以后能推出类似的技术,在开发微信小程序的同时,也可以同时开发基于HTML5的微信公众号(目前腾讯推出的最新小程序IDE已经支持类似的功能了,不过功能不算太强)。
通过原生热布局的应用,App的性能完全可以和原生App(其实就是动态生成的原生组件)相媲美,目前已经有很多类似的框架问世,以后可能会更多。相信这些原生热布局的方式会在今后很长一段时间内成为跨平台开发的主流,因为它的“颜值”实在太高了!
在开发小程序之前,需要注册一个小程序账号,并用与账号绑定的手机微信扫描开发工具的二维码才能登录开发小程序的IDE(将在1.4节介绍)。
首先进入如下地址的页面。
如果已经用微信公众号登录,请注销。然后单击右上角“立即注册”链接,进入注册页面。该页面有如图1-1所示的4个注册选项,分别是订阅号、服务号、小程序和企业号。
▲图1-1 注册类型
也就是说,这4个注册类型需要使用4个不同的账号,如果读者已经有了订阅号或其他账号,仍然需要再次注册小程序账号。
现在单击“小程序”选项,系统会让你输入邮箱、密码、验证码等信息,这些都是注册的常规流程,这里不再赘述。然后单击下方的“注册”按钮,系统会发送一封电子邮件到你输入的邮箱中,单击邮件中的链接,会进入填写注册信息页面。目前小程序的账号注册并不对个人开放,只对如图1-2所示的4种类型的组织开放。
▲图1-2 小程序账号支持的组织类型
如果读者有自己的企业,或是为单位注册,可以选择相应的类型。选择其他类型需要相关的资质证明,如果选择企业需要企业营业执照等信息。
在注册的过程中要用企业账户向腾讯官方提供的账号打款0.06元进行验证(要求在10天之内打款,否则验证失败,注意只能是0.06元)。不管验证是否成功,钱款都会退回到原来的企业账户。验证是自动的,但并不是实时的。腾讯的服务端应该是隔一段时间进行一次验证,可能会等几个小时,请耐心等待。
在验证通过之前,仍然可以用注册的邮箱登录小程序后台,但无法获取小程序的AppID。验证通过后,会通过站内短信(在小程序后台右上角)进行通知。要注意的是,登录小程序后台的过程中要使用手机微信扫描二维码进行登录,请用管理员的微信扫描登录小程序后台。
当成功注册小程序账号后,可以进入https://mp.weixin.qq.com页面进行登录,登录的过程中需要使用管理员的手机微信扫描二维码。刚登录进入小程序的后台管理页面,会看到如图1-3所示的主页面,左侧是一排功能菜单,单击右下角的“前往发布”可以发布小程序(在本章后续内容中会介绍)。
▲图1-3 小程序后台管理主页面
尽管开发小程序AppID并不是必须的,但如果要在真机上测试小程序,以及发布小程序,就必须要用到AppID了。这就和Apple的开发者账号一样,如果不花99$/年的费用购买开发者账号,你就只能在iOS模拟器上玩玩了。当然,小程序的AppID是不收费的,只要注册者满足资质,就可以免费注册,并获得AppID。
如果读者按着上一节的步骤成功注册了小程序账号,并登录到小程序后台管理页面。单击左下角的“设置”链接,在右侧单击“开发设置”选项卡,可以看到“开发者ID”列表,第一项“AppID(小程序ID)”后面就是AppID,如图1-4所示。
▲图1-4 AppID
这是我做的一个小程序(极客题库)的AppID,不过就算大家知道了这个AppID也用不了,因为登录时需要用管理员的微信扫描才可以,或者成为该项目的开发者,否则是无法使用别人的AppID的。
即使有了AppID,也不能立即发布小程序,在此之前,还需要设置小程序的基本信息。单击“设置”链接,在右侧单击“基本设置”,会出现一些设置项,如小程序名称、小程序头像等。设置完成后,会出现类似图1-5所示的信息。
▲图1-5 小程序基本设置
当小程序发布后,如果想让别人使用你的小程序,最简单的方式就是提供小程序的二维码。单击图1-5所示页面“二维码”右侧的“下载更多尺寸”,可以下载不同尺寸的二维码。图1-6是“极客题库”的二维码,大家可以扫一扫,看看能不能运行小程序。
▲图1-6 “极客题库”小程序二维码
本节将从零开始开发一款微信小程序。该程序是一个猜拳游戏,功能很简单,单击“开始”按钮后,会快速切换“锤子”“剪刀”和“布”,直到按“停止”按钮,会显示“锤子”“剪刀”和“布”中的一个,该游戏可以实现双方或多方猜拳。本节的目的是通过该例子,将开发微信小程序的过程完整讲述一遍,从配置开发环境、建立小程序项目,一直到将微信小程序发布到微信平台,并在真机上测试为止。通过该例子,读者可以掌握微信小程序的开发流程。
腾讯在推出微信小程序的同时,也推出了自己的开发工具,读者可以到下面的地址中下载该开发工具的最新版本。
https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=1477656486010
这套开发工具目前支持Windows32位、Windows64位以及Mac OS X系统,读者需要根据自己使用的OS下载合适的版本。本书主要使用Mac OS X版本进行讲解,Windows版本和Mac OS X大同小异,并不影响读者阅读本书的内容。
运行微信小程序IDE后,会看到如图1-7所示的窗口。
▲图1-7 扫描二维码进入IDE
进入手机微信,扫描该二维码(需要管理员微信账号才可以正常登录),就会自动登录,并进入如图1-8所示的窗口。
▲图1-8 微信开发者工具
目前该工具同时支持开发小程序和公众号网页开发,由于本书主要讲解小程序开发,所以读者要选择第一项“本地小程序项目”,进入如图1-9所示的窗口。
▲图1-9 微信小程序IDE建立项目窗口
读者如果第一次使用该IDE,可以单击“添加项目”,新建一个小程序项目,图1-9所示的列表是已经建立的小程序项目。
单击“添加项目”后,会看到如图1-10所示的页面。
▲图1-10 新建小程序项目
进入如图1-10所示的新建项目窗口后,如果读者有小程序的AppID,可以直接在AppID中输入。如果没有,单击“无AppID”,也可以开发小程序,只是无法在真机上测试,也无法发布,但可以在本地运行。最后按图1-11所示输入项目名称和项目目录。
▲图1-11 输入小程序工程信息
单击“添加项目”按钮后,会创建新的小程序项目,开发主界面如图1-12所示。下一节我们会在这个项目中开发第一个小程序,并介绍该开发界面的主要组成部分。
▲图1-12 微信小程序开发主界面
进入小程序IDE,单击IDE左上角的“编辑”选项(如图1-13所示),开始编辑代码。
猜拳游戏的布局非常简单,如图1-14所示。
▲图1-13 IDE左上角的控制选项
▲图1-14 猜拳游戏的布局样式
猜拳游戏的布局是纵向显示了3个组件:文本组件(text)、图像组件(image)和按钮组件(button)。在创建小程序工程时,默认建立了两个页面:index和logs,如图1-15所示。我们不需要考虑logs,在这个例子中只修改和index页面相关的文件。index是小程序第一个显示的页面。
▲图1-15 index和logs页面的文件结构
其中,index.wxml文件是index页面的布局文件,现在打开该文件,并按下面的内容修改代码。
<!--index.wxml-->
<view class="container">
<text class="finger_guessing">猜拳游戏</text>
<view class="userinfo">
<image class="userinfo-avatar" src="{{imagePath}}" background-size="cover"/>
<button bindtap="guess">{{title}}</button>
</view>
</view>
在这段代码中,image和button组件的内容都需要动态改变,所以image组件的src属性和button组件的文本值(夹在<button>和</button>之间的部分)都分别与一个变量绑定。这是小程序的一个重要特性(和React Native完全相同)。在改变组件的属性值时,并不需要直接获取该组件的实例,而只需将该属性与某个同类型的变量绑定,一旦该变量的值改变,属性值也就会随之改变了。绑定变量的格式是“{{变量名}}”。改变了的定义和初始化部分,在下一节会详细介绍。
我们发现,就算按前面的布局,仍然不能像图1-14所示那样摆放组件,这是因为还需要调整下面代码的样式(index.wxss文件)。
/**index.wxss**/
.userinfo {
display: flex;
flex-direction: column;
align-items:center;
margin-top: 50px;
}
.userinfo-avatar {
width: 500rpx;
height: 500rpx;
margin: 40rpx;
}
.userinfo-nickname {
color: #aaa;
}
.finger_guessing {
color: #F00;
font-size: 30px;
margin-top: 20px;
}
前面的布局代码主要调整了userinfo-avatar的宽度和高度,让图像显示得更大一些。
最后,还需要修改app.wxss文件的代码,将padding属性的值改成50rpx 0,代码如下:
/**app.wxss**/
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 50rpx 0;
box-sizing: border-box;
}
当然,现在可能仍然无法显示图像,因为还没有设置imagePath变量,而且还没有把图像放到工程目录中。现在读者可以到网上找3张图片,分别是剪子、石头和布,当然,也可以用本例提供的图像,并在小程序工程根目录建立一个images目录,将这3个图像文件放到该目录中。
猜拳游戏的核心就是快速切换剪子、石头、布3个图像,当单击“停止”按钮后,会停到其中一个图像上。这里涉及到如下两个动作:
控制图像快速切换和按钮文本变化两个动作的代码都要写在index.js文件中。首先会将这3个图像文件名存储在一个全局的数组中,并使用定时器快速从这个数组中依次循环获取图像文件名,并将该文件名指定的图像显示到image组件中。修改按钮的文本只需要修改title变量即可。
这里涉及到两个主要变量:imagePath和title。这两个都定义在data对象中,单击按钮会执行guess函数(在index.wxml文件中使用bindtap属性指定按钮的单击事件函数名),该函数也需要在index.js中编写。完整的实现代码如下:
//index.js
//获取应用实例
var app = getApp()
// 在数组中存在三个图像文件名
var imagePaths = ['../../images/scissors.png', '../../images/stone.png', '../../images/cloth.png'];
// 当前图像的索引
var imageIndex = 0;
Page({
data: {
imagePath: imagePaths[0], // 用于修改image组件显示图像的变量
title: '开始', // 用于改变按钮文本的变量
isRunning:false, // 该变量为true,表示图像正在快速切换
userInfo: {},
},
//事件处理函数
bindViewTap: function () {
wx.navigateTo({
url: '../logs/logs'
})
},
// 定时器要执行的函数
change: function (e) {
imageIndex++;
// 当前图像索引大于最大索引时,重新设为第一个索引值(已达到循环显示图像的目的)
if (imageIndex > 2) {
imageIndex = 0;
}
// 修改image组件要显示的图像(改变imagePath变量的值)
this.setData(
{
imagePath: imagePaths[imageIndex]
}
)
},
// 单击按钮要执行的函数——单击要执行的函数按钮
guess: function (e) {
// 获取isRunning变量的值
let isRunning = this.data.isRunning;
// 根据是否正在快速切换图像,决定如何修改按钮文本,以及是开启定时器,还是移除定时器
if (!isRunning) {
this.setData(
{
title: '停止',
isRunning:true
}
);
// 开启定时器(没100毫秒调用一次change函数)
this.timer = setInterval((function () {
this.change()
}).bind(this), 100);
}
else {
this.setData(
{
title: '开始',
isRunning:false
}
);
// 移除定时器
this.timer && clearInterval(this.timer);
}
},
onLoad: function () {
console.log('onLoad')
var that = this
//调用应用实例的方法获取全局数据
app.getUserInfo(function (userInfo) {
//更新数据
that.setData({
userInfo: userInfo
})
})
}
})
至此,猜拳游戏的代码已全部介绍完毕,现在可以通过左侧的模拟器测试我们的成果了。大家可以单击“开始”按钮,看看图像是否会快速切换,再单击“停止”按钮,看看是否会停止在某个图像上。
现在轮到用真机测试我们的成果了。如果只想在真机上测试,可以用管理员微信登录小程序IDE。
现在单击IDE左上角的“项目”选项,右侧会显示如图1-16所示的项目操作页面。
▲图1-16 项目操作页面
单击“预览”按钮,会显示如图1-17所示的二维码窗口,用管理员的微信扫描该二维码,即可将小程序上传到真机上运行。
在真机(Android手机)上的测试结果如图1-18所示。
▲图1-17 扫描二维码上传小程序到真机
▲图1-18 在真机上的测试结果
如果在模拟器上开发小程序,很容易在Console中查看调试信息,但如果在真机上运行呢?其实也有办法查看调试信息。现在按着前面讲解步骤在真机上运行小程序,然后单击右上角的省略号(…)菜单,会弹出如图1-19所示的菜单。
单击“打开调试”菜单项,这时当前小程序需要关闭,然后重新进入。这时会看到右下角有一个绿色的“vConsole”按钮,如图1-20所示。
▲图1-19 功能菜单
▲图1-20 vConsole按钮
单击“vConsole”按钮,就会打开真机上的Console,并显示调试信息,如图1-21所示。关闭Console,执行同样的操作即可。
▲图1-21 真机上的Console
如果在真机上测试没问题,那么可以单击图1-16所示的“上传”按钮将小程序上传到腾讯的服务器。单击“上传”按钮后,也会显示一个类似图1-17的二维码窗口,用管理员的微信扫描该二维码,然后会显示如图1-22所示的窗口,输入相应的版本号和项目备注,最后单击“上传”按钮上传即可。
▲图1-22 完成最后的上传设置工作
成功上传小程序后,回到小程序的后台,单击左侧的“开发管理”选项,会看到如图1-23所示的3个小程序版本的管理页面。我们直接上传的是开发版本,如果管理员认为没问题,可以单击“提交审核”按钮,将小程序提交给腾讯,这就是审核版本。如果腾讯审核通过正式上线了,这就是线上版本。读者也可以单击“提交审核”按钮右侧的向下箭头按钮,并单击“删除”按钮删除当前开发版本。要注意的是,下一次上传的版本会覆盖当前的开发版本。
▲图1-23 管理小程序的版本
本章用一个完整的例子从头到尾演示了从开发小程序到真机测试,再到上传发布的完整过程。尽管本章提供的例子非常简单,但足以清楚地展示小程序开发的完整过程。不过要想开发更加高级的小程序,还需要继续阅读后续的章节。
如果读者想了解完整的小程序账号注册、开发以及使用第三方发布的小程序的完整过程,可以观看我的视频课程:http://edu.csdn.net/course/detail/3371。
布局是任何支持UI的技术都会涉及到的。小程序的布局采用了和React Native相同的flex(弹性布局)方式,使用方法也类似(只是属性名不同而已)。因此,如果读者已经对React Native的布局比较了解,那么将非常容易掌握小程序布局。即使对React Native的布局不了解,通过对本章的学习,也可以掌握小程序布局的核心技术。
小程序的布局和React Native的布局类似,采用了弹性布局的方法,即分为水平和垂直布局。默认是从左向右水平依次放置组件,或从上到下依次放置组件。
wxml文件用于放置参与布局的组件,为了更好地描述小程序是如何布局的,本章使用了带背景色的view组件来演示。view是小程序中所有可视组件的根。
任何可视组件都需要使用样式来设置自身的属性,并完成相应的布局。在小程序中,可以使用两种方式设置样式,一种是class属性,另一种是style属性。前者需要指定在wxss文件中定义的样式,后者允许直接在组件中定义样式属性。例如,如果要水平放置3个view组件,可以在wxml文件中使用下面的代码。
<view class="flex-wrp" style="flex-direction:row">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
显示的效果如图2-1所示。
▲图2-1 水平布局
在上面的代码中,同时使用了class和style属性。分别指定了样式flex-wrp和样式属性flex-direction:row,其中,后者表示view中的子组件要按水平排列。flex-wrp的定义如下:
.flex-wrp{
height: 100px;
display:flex;
background-color: #FFFFFF;
}
其中,display:flex表示弹性布局,flex是Flexible的缩写。
如果class属性需要指定多个样式,样式直接用空格分隔,代码如下:
<view class="flex-item bc_green"></view>
其中flex-item的代码如下:
.flex-item{
width: 100px;
height: 100px;
}
前面所有的样式都是在当前页面的index.wxss文件中定义的,而bc_green以及其他几个设置颜色的样式是在app.wxss文件中定义的,所有的页面都可以使用。
.bc_green{
background-color: #09BB07;
}
.bc_red{
background-color: #F76260;
}
.bc_blue{
background-color: #10AEFF;
}
.bc_yellow{
background-color: #FFBE00;
}
.bc_gray{
background-color: #C9C9C9;
}
如果不想使用style属性,可以将flex-direction:row放在样式中。例如,可以在index.wxss文件中添加如下的样式。
.flex-row{
flex-direction:row;
}
然后修改index.wxml文件中的代码如下:
<view class="flex-wrp flex-row" >
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
可能很多读者会发现一个问题,本节的例子中只有3个view,如果放置了多个view会怎么样呢?从flex-item样式可知,每个view的尺寸是100*100,单位是像素(px),如果放置过多,可能会发生如下两种情况:
那么到底会发生哪种情况呢?我们不妨做一个实验,代码如下:
<view class="flex-wrp flex-row" >
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
在上述代码中,view中包含了9个子view,保存index.wxml文件后,会显示如图2-2所示的效果。
▲图2-2 压缩了每一个view的宽度
很明显,每一个view的宽度都被压缩了(因为每一个view的默认尺寸是一个正方形),以适应设备的宽度。不过这种处理方式可能并不符合我们的要求,如果我们的要求是让每一个view的尺寸保持不变,但是一行放不下,怎么能够折到下一行呢?答案就在下一节!
要想让view折行也很简单,只需要加一个flex-wrap:wrap即可,代码如下:
<view class="flex-wrp flex-row" style="flex-wrap:wrap" >
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
或者将flex-wrap:wrap添加到flex-row样式中,代码如下:
.flex-row{
flex-direction:row;
flex-wrap:wrap;
}
修改后的运行效果如图2-3所示。
▲图2-3 折行水平排列
只需要设置flex-direction的值为column,就可以将水平排列改成垂直排列,代码如下:
<view class="flex-wrp" style="height: 300px;flex-direction:column;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
在这段代码中,将顶层view的高度设为300px,而每一个子view的高度是100px,所以垂直方向3个view会紧挨着显示,效果如图2-4所示。
▲图2-4 垂直排列
在垂直方向,如果子view过多会怎么样呢?如下面代码所示。
<view class="flex-wrp" style="height: 300px;flex-direction:column;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
如果使用上述的布局,会看到如图2-5所示的显示效果。
▲图2-5 被压缩的垂直排列
很明显,所有的子view都被压缩在垂直高度300px的空间内(宽度未改变),能否让垂直排列的子view折列呢?请看下一节的介绍。
折列和折行的方式一样,只需要加上flex-wrap:wrap即可,可以使用style属性添加,或在样式中添加,然后使用class属性引用样式。下面的代码使用style属性添加了flex-wrap:wrap。
<view class="flex-wrp" style="height: 300px;flex-direction:column; flex-wrap:wrap;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
使用上面的布局后,会看到如图2-6所示的效果。
▲图2-6 垂直折列排列
从图2-6所示的效果可以看出,折列排列是在第2、3列从上到下依次排列的。
前文所述的水平排列都是从左侧开始排列的,这是默认的对齐方式:左对齐。这种对齐方式是默认的,或在style属性中加入justify-content: flex-start,代码如下:
<view class="flex-wrp" style="flex-direction:row;justify-content: flex-start;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
除了左对齐,还有右对齐和中心对齐,只需要将justify-content的值改成flex-end或center,即可实现右对齐或中心对齐的效果。右对齐的布局代码如下:
<view class="flex-wrp" style="flex-direction:row;justify-content: flex-end;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
右对齐的效果如图2-7所示。
▲图2-7 右对齐
中心对齐的代码布局代码如下:
<view class="flex-wrp" style="flex-direction:row;justify-content: center;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
中心对齐的效果如图2-8所示。
▲图2-8 中心对齐
对于垂直排列来说,如果改变对齐方式,是否可以采用水平排列的方式呢?例如,下面的布局代码是否有效呢?
<view class="flex-wrp" style="flex-direction:column;justify-content: flex-end;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
保存文件后,会看到如图2-9所示的效果。
▲图2-9 没有改变对齐方式的垂直排列
很显然,垂直排列的3个view并没有右对齐。对于垂直排列来说,需要使用align-items属性(默认是左对齐),而不是justify-content属性,这两个属性的取值基本上相同。例如,下面的布局代码让3个垂直排列的view右对齐。
<view class="flex-wrp" style="flex-direction:column;align-items: flex-end;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
垂直排列右对齐的效果如图2-10所示。
▲图2-10 垂直排列右对齐
下面的布局代码让垂直排列中心对齐。
<view class="flex-wrp" style="flex-direction:column;align-items: center;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
垂直排列中心对齐的效果如图2-11所示。
▲图2-11 垂直排列中心对齐
如果垂直排列是右对齐或中心对齐的方式,那么如果折列会是什么效果呢?例如,下面的布局代码垂直方向右对齐,并且折列。
<view class="flex-wrp"
style="height:300px;flex-direction:column;align-items: flex-end;flex-wrap:wrap;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
</view>
运行效果如图2-12所示。
▲图2-12 垂直方向右对齐,并且折列
从图2-12所示的效果来看,即使是右对齐,如果需要折列,显示的第一列仍然是从靠左方向开始的(从view的背景色就可以看出,第4个view的背景色是蓝色),然后向右折列(但最后一列需要紧贴着父视图右边缘,因为是右对齐)。如果是中心对齐,方式相同。
下面是中心对齐,并且折列的布局代码。
<view class="flex-wrp"
style="height:300px;flex-direction:column;align-items: center;flex-wrap:wrap;">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
</view>
显示效果如图2-13所示。
▲图2-13 垂直方向中心对齐,并且折列
如果想让view均匀地水平分别在窗口上,且每两个view之间的间隔相同,那么需要将justify-content属性的值设为space-between,布局代码如下:
<view class="flex-wrp" style="flex-direction:row;justify-content: space-between">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
显示的效果如图2-14所示。
▲图2-14 space-between效果
如果子view过多,并且设置为折行显示,那么子view会如何排列呢?先看下面的布局代码。
<view class="flex-wrp"
style="flex-direction:row;justify-content: space-between;flex-wrap:wrap">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_blue"></view>
</view>
使用上述的布局,会得到如图2-15所示的效果。
▲图2-15 折行后的space-between效果
从图2-15所示的效果来看,不管折多少行,同一行相邻两个view之间的间距都是相等的。
上一节介绍的space-between是顶格显示的,也就是说,最左边和最右边的view是紧挨着父视图边缘的。当我们想留一定的边距时,需要使用space-around,布局代码如下:
<view class="flex-wrp" style="flex-direction:row;justify-content: space-around">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
</view>
运行效果如图2-16所示。
▲图2-16 space-around效果
如果发生折行,仍然是每一行的最左侧和最右侧都会距父视图边缘有一定距离,布局代码如下:
<view class="flex-wrp"
style="flex-direction:row;justify-content: space-around;flex-wrap:wrap">
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_blue"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_red"></view>
<view class="flex-item bc_green"></view>
<view class="flex-item bc_blue"></view>
</view>
显示效果如图2-17所示。
▲图2-17 折行后的space-around效果
本章主要介绍了小程序中的主要布局方式,通过这些布局,可以设计出各式各样的UI。尽管本章中并没有一行JavaScript代码,但也相当重要。因为如果不掌握布局,后面的组件掌握得再熟练都没用,所以如果读者对小程序的布局还不了解,建议详细阅读本章。