【微信小程序】开发实战 之 「配置项」与「逻辑层」
微信小程序作为微信生态重要的一环,在实际生活、工作、商业中的应用越来越广泛。想学习微信小程序开发的朋友也越来越多,本文将在小程序框架的基础上就微信小程序项目开发所必需的基础知识及语法特点进行了详细总结和阐述,包括配置、函数、语法、事件及其处理、数据绑定、模块、样式等。想开发小程序,这些内容是必须掌握的。
全文知识结构预览:
一、程序配置:
1、全局配置;2、页面配置
二、逻辑层:
1、程序注册:App()方法;2、页面注册:Page()方法;3、模块与调用;4、微信原生API
三、视图层(将在单独文章中阐述)
一、程序配置
1、全局配置
先来看一个典型的全局配置app.jason文件内容:
{ "pages":[ "pages/index/index", "pages/logs/logs" ], "window":{ "navigationBarTitleText":"Demo", "navigationBarTextStyle": "black" }, "tabBar":{ "list":[{ "pagePath":"pages/index/index", "text":"首页" },{ "pagePath":"pages/logs/logs", "text":"日志" }] }, "networkTimeout":{ "request":10000, "downloadFile":"10000" }, "debug":true }
如上所示,小程序的全局配置是保存在app.jason文件中的。
从文件内容可以看出小程序的全局配置局并不多,包括页面路径(page)、窗口表现(window)、切换页签(tabBar)、网络超时设定(networkTimeout)、调试模式(debug)。而且并不是每一项配置都是必需的。
在详细介绍每一个配置项之前,先说一下小程序里JSON配置的一些注意事项。
JSON文件都是被包裹在一个大括号中 {},通过key-value的方式来表达数据。JSON的Key必须包裹在一个“双引号”中,在实践中,编写 JSON 的时候,忘了给 Key 值加双引号或者是把双引号写成单引号是常见错误。
JSON的值只能是以下几种数据格式,其他任何格式都会触发报错,例如 JavaScript 中的 undefined。
- 数字,包含浮点数和整数
- 字符串,需要包裹在双引号中
- Bool值,true 或者 false
- 数组,需要包裹在方括号中 []
- 对象,需要包裹在大括号中 {}
- Null
还需要注意的是 JSON 文件中无法使用注释,试图添加注释将会引发报错。
下面我们详细说明一下app.jason中每个配置项的类型及注意事件:
1.1 pages配置项
pages是程序必需的配置项。pages接受一个数组(Array),用来指定小程序由哪些页面组成。数组的每一项都是字符串类型,代表对应页面的“路径+文件名”。
pages配置时需要注意以下三点:
a)数组第一项即小程序的启动页,即首页;
b)小程序新增或减少页面,都需要修改pages数组;
c)文件名不需要加后缀,如"pages/index/index",小程序框架会自动寻找路径下的四类文件(.js/.jason/.wxml/.wxss)进行整合。
1.2 window配置项
window不是必需的配置项。没有配置时系统将采用默认值。window接受对象值(Object),用来设置小程序的状态栏、导航栏、标题、窗口等对象的颜色、背景、内容属性。
window的可配置的对象及其描述如下:
a)navigationBarBackgroundColor,设置导航栏背景颜色,value类型HexColor,默认值#000000;
b)navigationBarTextStyle,设置导航栏标题颜色,value类型String,仅支持black或white;
c)navigationBarTitleText,设置导航栏标题文字内容,value类型String;
d)backgroundColor,设置窗口的背景色,value类型HexColor,默认值#ffffff;
e)backgroundTextStyle,下拉背景字体、loading图的样式,value类型String,仅支持dark/light;
f)ebablePullDownRefresh,是否开启下拉刷新,value类型Boolean,默认值false。
示例:我们在app.jason中设置如下的window配置:
"window": { "navigationBarBackgroundColor": "#405f80", "navigationBarTextStyle": "white", "navigationBarTitleText": "光与影", "backgroundColor":"#eeeeee", "backgroundTextStyle":"light" }
则小程序产生的界面效果如图:
1.3 tabBar配置项
tabBar配置项可以实现小程序多页签切换的功能。tabBar用来指定标签页的样式以及切换时对应的页面。
tabBar配置项及其说明:
a)color,设置标签上的文字默认颜色,value类型HexColor,必填项;
b)selectedColor,设置标签上的文字选中时的颜色,value类型HexColor,必填项;
c)backgroundColor,标签页的背景色,value类型HexColor,必填项;
d)boderStyle,标签的框线颜色,value类型String,默认值black,仅支持black或white,选填;
e)position,标签栏的位置,value类型String,默认值bottom,可选值bottom或top,选填;
f)list,标签页列表,value类型Array,支持最少2个、最多5个标签页。
需要注意的是,list接受的是一个数组值,数组元素的顺序就是标签页显示的顺序,数组中的每一项也都是一个对象,其类型、功能描述如下(均是必填项):
a)pagePath,页面路径,需要在pages中预定义,value类型String;
b)text,标签上按钮文字,value类型String;
c)iconPath,标签上icon图标路径,图标大小不能超过40KB,value类型String;
d)selectedIconPath,标签被选中时显示的icon图标路径,图标大小不能超过40KB,value类型String;
下面的示例设置了2个标签页“阅读”和“电影”,代码如下:
"tabBar": { "color":"#dddddd", "selectedColor":"#3cc51f", "borderStyle": "white", "backgroundColor":"#ffffff", "list": [ { "pagePath": "pages/posts/post", "text": "阅读", "iconPath": "/images/tab/yuedu.png", "selectedIconPath": "/images/tab/yuedu_hl.png" }, { "pagePath": "pages/movies/movies", "text": "电影", "iconPath": "/images/tab/dianying.png", "selectedIconPath": "/images/tab/dianying_hl.png" } ] }
界面的实际效果如下图所示:
1.4 networkTimeout配置项
networkTimeout用于设置各种网络请求对象的超时时间,非必须配置项。可以设置网络请求超时的相关对象有request、connectSocket、uploadFile、downloadFile。时间单位均为毫秒。当然,这些超时若没有设置, 则默认使用操作系统内核或遵循服务器WebServer的设定值。
1.5 debug配置项
debug配置项用于是否开启开发者工具的调试模式。它的value类型是一个boolean值,默认是false。开启后,页面page的注册、页面路由、数据更新、事件触发等调试信息将以info的形式,输出在调试功能的console面板上。开启配置如下:
{ "debug":true }
显然开启后调试模式后,对开发者快速定位一些常见问题很有帮助,但在正式发布时应当关闭此配置项开关。
2、页面配置
小程序中的页面配置page.jason,只能设置本页面的窗口表现,也就是只能设置window配置项的内容。页面.jason文件中的window配置值将覆盖app.jason中的配置值。
因为页面.jason文件中只能设置window配置项,以决定本页面的窗口表现,所以文件中也无需写window这个键值,直接写window下的可配置项即可。window的可配置项已在本文(1.2)小节中说明。
二、逻辑层
关于小程序逻辑层的概念和特点,在微信小程序开发框架(MINA)中已做阐述,此处不再赘述。
1、注册程序的App()方法
先来看一下App()方法的代码示例:
App({ onLaunch:function(){ //程序启动时执行的初始化操作 }, onShow:function(){ //程序进入前台时执行的操作 }, onHide:function(){ //程序进入后台时执行的操作 }, onError:function(msg){ console.log(msg) }, globalData:'This is global data' })
PS:前台、后台:用户操作小程序的当前界面称之为前台,当点击关闭或按HOME键离开微信,小程序并没有直接销毁,而是进入后台;当再次进入微信或再次打开小程序,又会从后台进入前台了。
App()方法用来注册一个程序,且只能注册一次,存在于app.js中。它接受的参数是object类型:
a)onLaunch,生命周期函数,监听小程序初始化,当小程序初始化完成时,会触发onLaunch,且全局只触发一次;
b)onShow,生命周期函数,监听小程序显示,小程序启动或从后台进入前台显示,会触发onShow;
c)onHide,生命周期函数,监听小程序隐藏,小程序从前台进入后台会触发onHide;
d)onError,错误监听函数,小程序发生脚本错误或API调用失败,会触发onError并带出错误信息;
e)开发者还可以添加任意object类型的参数,用this访问;
可以使用全局函数getApp()获取小程序实例。使用示例如下:
//**.js var app = getApp() console.log(app.globalData) //输出'This is global data'
但是在App()函数中不要使用getApp(),使用this就可以拿到App()实例。
2、注册页面的page()方法
先来看一下page()方法的代码示例:
Page({ data:{ text:"This is page data." }, onLoad:function(){ //页面加载时执行的初始化操作 }, onReady:function(){ //页面初次渲染时执行的操作 }, onShow:function(){ //页面显示时执行的操作 }, onHide:function(){ //页面隐藏时执行的操作 }, onUnload:function(){ //页面卸载或关闭时执行的操作 }, onPullDownRefresh:function(){ //页面被用户下拉时执行的操作 }, onReachBottom:function(){ //页面到达底部时执行的操作 }, onShareAppMessage:function(){ //用户分享时返回个性化的分享数据 }, //响应wxml绑定事件处理 viewTap:function(){ this.setData({ text:'Set some data for update view' }) } })
page()方法用来注册一个页面。它接受object类型参数,用来指定页面的初始数据、生命周期函数、事件处理函数等。每个页面有且仅有一个page()方法,存在于该页面的.js文件中。
2.1 初始化数据
data参数提供页面的初始化数据,作为页面的第一次渲染。对象 data 将会以 JASON 的形式由逻辑层传至视图层,所以其数据必须是可以转成 JASON 的格式:字符串、数字、布尔值、对象、数组。
在视图层通过WXML对数据进行绑定。示例代码如下:
<!--wxml--> //渲染page()的数据 <view>{{text}}</view>
2.2 页面生命周期函数
页面的生命周期包括:onLoad、onShow、onReady、onHide、onUnload。
onLoad是页面加载时执行的初始化操作。一个页面只会调用一次,参数可以获取wx.navigationTo和wx.redirectTo及<navigator />中的query。
onShow是页面显示时执行的操作。每次打开页面都会调用一次。
onReady是页面渲染完成时执行的操作。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。对页面的设置(如wx.setNavigationBarTitle)应该在onReady之后。
onHide是页面隐藏时执行的操作。当进行 navigateTo 或底部进行 tab 切换时调用。
onUnload是页面卸载时执行的操作。当进行 redirectTo 或 navigateBack 操作时调用。
2.3 页面相关事件处理函数
onPullDownRefresh是下拉刷新时执行的操作,监听用户下拉刷新事件。需要在页面 .json 文件的window配置项中开启enablePullDownRefresh。当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。
onShareAppMessage是用户分享时返回定制的分享内容。只有定义了此事件处理函数,右上角菜单才会显示“分享”按钮。用户点击分享按钮的时候会调用。此事件需要return一个object对象,用于自定义分享内容。
title 是分享的标题,默认值是当前小程序的名称。
path 是分享路径,当前页面的 path,必须是以 / 开头的完整路径。
onShareMessage示例代码如下:
page({ onShareMessage:function(){ return{ title:'分享标题', path:'/page/url?id=5' } } })
2.4 视图层绑定的事件处理函数
page()方法除了初始化数据和生命周期函数,还可以定义一些特殊的事件处理函数。我们可以在视图层通过对组件加入事件绑定,当满足触发事件时,就会执行page()中定义的事件处理函数。
示例代码如下:
<!--wxml 绑定tap事件到view组件上,函数名为viewTap--> <view bindtap = "viewTap"> click me </view> //page.js page({ //定义 viewTap 事件处理函数 viewTap:function(){ console.log('view tap') } })
2.5 页面数据设置与展现
在page()中我们使用setData函数来设置数据。改变对应的this.data的值。
this是指包含它的函数作为方法被调用时所属的对象,在小程序中一般指调用页面。
不能直接修改this.data,这样无法改变页面的状态,还会造成数据不一致。
尽量避免一次设置过多的数据,单次不能超过1024KB。
setData函数参数是对象类型。以key、value的形式表示,将this.data中的key对应的值改变成value。其中key无须在this.data中预定义。
示例代码如下:
<!--index.wxml--> <view>{{text}}</view> <button bindtap = "changeText">Change normal data</button> <view>{{array[0].text}}</view> <button bindtap = "changeItemInArray">Change Array data</button> <view>{{object.text}}</view> <button bindtap = "changeItemInObject">Change Object data</button> <view>{{newField.text}}</view> <button bindtap = "addNewField">Add new data</button> //index.js page({ data:{ texe:'init data', array:[{text:'init data'}], object:{ text:'init data' } }, changeText:function(){ //this.data.text = 'changed data'错误设置方法 this.setData({ text:'changed data' }) }, changeItemInArray:function(){ //注意修改的key是数据路径的形式(有引号) this.setData({ 'array[0].text':'changed data' }) }, changeItemInObject:function(){ //注意修改的key是数据路径的形式(有引号) this.setData({ 'object.text':'changed data' }) }, addNewField:function(){ //注意添加的key是数据路径的形式(有引号) this.setData({ 'newField.text':'new data' }) } })
实际效果示例:
2.6 页面栈及其实例获取
框架以栈的形式维护了程序的所有页面。当发生页面切换的时候,页面栈的表现如下:
路由方式 | 页面栈表现 |
初始化 | 新页面入栈。 |
打开新页面 | 新页面入栈。 |
页面重定向 | 当前页面出栈,新页面入栈。 |
页面返回 | 页面不断出栈,直到目标返回,新页面入栈。 |
Tab 切换 | 当前页面出栈,新页面入栈。 |
框架提供了获取当前页面栈实例的方法getCurrentPages(),页面以数组形式按栈的形式给出,第一个元素为首页,最后一个元素为当前页面。不要尝试修改页面栈,会导致路由及页面状态错误。
2.7 页面路由
小程序框架管理所有页面的路由。路由的触发方式以及页面的生命周期函数对应关系如下:
路由方式 | 触发时机 | 路由后页面 | 路由前页面 |
初始化 | 小程序打开的第一个页面 | onLoad,onShow | |
打开新页面 |
调用API wx.navigateTo 或 使用组件<navigator open-type="navigator"/> |
onLoad,onShow | onHide |
页面重定向 |
调用API wx.navigateTo 或 使用组件<navigator open-type="navigator"/> |
onLoad,onShow | onUnload |
页面返回 |
调用API wx.navigateTo 或 用户按左上角返回按钮 |
onShow | onUnload |
Tab 切换 |
调用API wx.switchTab 或使用组件<navigator open-type="switchTab"/> 或多 Tab 模式下用户切换Tab |
第一次打开 onLoad,onShow; 否则 onShow |
onHide |
3、模块化与调用
3.1 文件作用域
在页面的JavaScript脚本文件(.js)中声明的变量和函数只在该文件中有效,不同的文件中可以声明相同名字的变量和函数,不会互相影响。
通过全局函数getApp()可以获取全局的应用实例,如果需要全局的数据可以在App()方法中设置,例如:
//app.js App({ globalData:1 }) //a.js //在a.js中定义变量localValue var localValue = 'a' //在a.js中获取App实例 var app = getApp() //修改a.js中获取到的全局数据值 app.globalData++ //b.js //在b.js中定义变量localValue,不影响a.js中的localValue var localValue = 'b' //假设a.js在b.js之前运行,那么下面的语句之后globalData就会是2 console.log(getApp().globalData)
3.2 模块化
我们可以将一些公共的代码抽离成为一个单独的.js脚本文件,作为一个模块。
模块只有通过 module.exports 才能对外暴露接口以供其他.js文件引入使用。在需要使用公共模块的.js文件中,使用 require(path)将公共代码引入。
示例代码如下:
//common.js function Hello(name) { console.log('Hello' + name + '!') } module.exports = { sayHello: Hello } //下面的call.js使用common.js模块 //call.js var common = require('common.js') page({ helloMINA:function(){ common.sayHello('MINA') } })
4、微信原生API
小程序开发框架提供了功能丰富的微信原生API,可以方便我们调取微信提供的能力,如获取用户信息、本地存储、支付等。
微信原生的API共有八大类:界面API、文件API、数据缓存API、媒体API、网络API、位置API、设备API以及微信开放接口。
微信API的共性特点:
wx.on开头的API是监听事件发生的API接口,接受一个回调函数(CALLBACK)作为参数。当事件发生时会调用该回调函数。
其他API接口都接受一个Object作为参数,除非有特殊约定。
Object中可以指定success、fail、complete方法来接收接口调用结果。success表示接口调用成功的回调函数,fail是接口调用失败的回调函数,complete是接口调用结束的回调函数且无论成功、失败都会执行。
关于原生API的种类、名称、作用的详细说明可以参考微信小程序开发者文档中的API部分。
以上阐述的是小程序开发基础中的「配置」与「逻辑层」部分,为避免篇幅过长,「视图层」部分的讲解将在单独的文章中予以讲述。