一、概述
小程序开发框架的逻辑层(App Service)由JavaScript编写;将数据进行处理后发给视图层,同时接受视图层的事件反馈。
小程序在JavaScript的基础上,变更如下:
增加 App 和 Page 方法,进行程序和页面的注册。
增加 getApp 和 getCurrentPages 方法,分别用来获取 App 实例和当前页面栈。
提供丰富的 API,如微信用户数据,扫一扫,支付等微信特有能力。
每个页面有独立的作用域,并提供模块化能力。
由于框架并非运行在浏览器中,所以 JavaScript 在 web 中一些能力都无法使用,如 document,window 等。
开发者写的所有代码最终将会打包成一份 JavaScript,并在小程序启动的时候运行,直到小程序销毁。类似 ServiceWorker,所以逻辑层也称之为 App Service。
二、注册程序
1.App()
该函数用来注册一个小程序,接受一个object参数,其指定小程序的生命周期函数等。
1.1前后台说明:
当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁,而是进入了后台;
当再次进入微信或再次打开小程序,又会从后台进入前台;
只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁;
关闭小程序:当用户从扫一扫、转发等入口(场景值为1007, 1008, 1011, 1025)进入小程序,且没有置顶小程序的情况下退出,小程序会被销毁。
1.2object参数说明:
onLaunch
类型:Function
描述:生命周期函数--监听小程序初始化
触发时机:当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
onShow
类型:Function
描述:生命周期函数--监听小程序显示
触发时机:当小程序启动,或从后台进入前台显示,会触发onShow
onHide
类型:Function
描述:生命周期函数--监听小程序隐藏
触发时机:当小程序从前台进入后台,会触发 onHide
onError
类型:Function
描述:错误监听函数
触发时机:当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
其他
类型:Any
触发时机:开发者可以添加任意的函数或数据到 Object 参数中,用 this 可以访问
App({
onLaunch: function(options) {
// Do something initial when launch.
},
onShow: function(options) {
// Do something when show.
},
onHide: function() {
// Do something when hide.
},
onError: function(msg) {
console.log(msg)
},
globalData: 'I am global data'
})
1.3 onLaunch、onShow参数
path String 打开小程序的路径
query Object 打开小程序的query
scene Number 打开小程序的场景值
shareTicket String shareTicket,详见 获取更多转发信息
referrerInfo Object 当场景为由从另一个小程序或公众号或App打开时,返回此字段
referrerInfo.appId String 来源小程序或公众号或App的 appId,详见下方说明
referrerInfo.extraData Object 来源小程序传过来的数据,scene=1037或1038时支持
以下场景支持返回referrerInfo.appId:
1020-公众号 profile 页相关小程序列表-返回来源公众号 appId
1035-公众号自定义菜单-返回来源公众号 appId
1036-App 分享消息卡片-返回来源应用 appId
1037-小程序打开小程序-返回来源小程序 appId
1038-从另一个小程序返回-返回来源小程序 appId
1043-公众号模板消息-返回来源公众号 appId
1.4 getApp()
全局的getApp()函数可以用来获取小程序实例。
//各个页面的.js
var appInstance = getApp()
console.log(appInstance.globalData)//全局数据
注意:
App() 必须在 app.js 中注册,且不能注册多个。
不要在定义于 App() 内的函数中调用 getApp() ,使用 this 就可以拿到 app 实例。
不要在 onLaunch 的时候调用 getCurrentPages(),此时 page 还没有生成。
通过 getApp() 获取实例之后,不要私自调用生命周期函数。
三、场景值scene
可以在App的onLaunch和onShow中获取场景值,部分场景值下还可以获取来源应用、公众号、小程序appId。
Android:由于系统限制,目前无法获取到按home键退出到桌面,然后从桌面再次进入小程序的场景值,这种情况,会保留上次的场景值。
四、注册页面-Page
1.Page()函数用来注册一个页面。接受一个 object 参数,其指定页面的初始数据、生命周期函数、事件处理函数等。
1.1 object参数说明:
object内容在页面加载时会进行一次深拷贝,需考虑数据大小对页面加载的开销
data-Object-页面的初始数据
onLoad-Function-生命周期函数--监听页面加载
onReady-Function-生命周期函数--监听页面初次渲染完成
onShow-Function-生命周期函数--监听页面显示
onHide-Function-生命周期函数--监听页面隐藏
onUnload-Function-生命周期函数--监听页面卸载
onPullDownRefresh-Function-页面相关事件处理函数--监听用户下拉动作
onReachBottom Function-页面上拉触底事件的处理函数
onShareAppMessage-Function-用户点击右上角转发
onPageScroll-Function-页面滚动触发事件的处理函数
onTabItemTap-Function-当前是 tab 页时,点击 tab 时触发
其他-Any-开发者可以添加任意的函数或数据到 object 参数中,在页面的函数中用 this 可以访问
index.js
Page({
data: {
text: "This is page data."
},
onLoad: function(options) {
// 页面加载 - 一个页面只会调用一次,可以在 onLoad 中获取打开当前页面所调用的 query 参数。
},
onReady: function() {
// 页面初次渲染完成 -
1.一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
2.对界面的设置如wx.setNavigationBarTitle请在onReady之后设置。详见生命周期
},
onShow: function() {
//页面显示 - 每次打开页面都会调用一次。
},
onHide: function() {
// 页面隐藏 - 当navigateTo或底部tab切换时调用。
},
onUnload: function() {
// 页面卸载 - 当redirectTo或navigateBack的时候调用。
},
/********页面相关事件处理函数*************/
onPullDownRefresh: function() {
//下拉刷新
1.监听用户下拉刷新事件。
2.需要在app.json的window选项中或页面配置中开启enablePullDownRefresh。
3.当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。
},
onReachBottom: function() {
// 上拉触底
1.监听用户上拉触底事件。
2.可以在app.json的window选项中或页面配置中设置触发距离onReachBottomDistance。
3.在触发距离内滑动期间,本事件只会被触发一次。
},
onShareAppMessage: function () {
// 用户转发
1.只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮
2.用户点击转发按钮的时候会调用
3.此事件需要 return 一个 Object,用于自定义转发内容:key:title - 转发标题 - 默认(当前小程序名称);key:path - 转发路径 - 当前页面path,必须是以/开头的完整路径;
eg:
return {
title: '自定义转发标题',
path: '/page/user?id=123'
}
},
onPageScroll: function() {
// 页面滚动
1.监听用户滑动页面事件。
2.参数为 Object,包含以下字段:scrollTop 类型(Number) 页面在垂直方向已滚动的距离(单位px)
},
onTabItemTap(item) {
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
/***************事件处理函数*******************/
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
},
customData: {
hi: 'MINA'
}
})
2.初始化数据
初始化数据将作为页面的第一次渲染,data将会以JSON的形式由逻辑层传至渲染层,所以其数据必须是可以转成JSON的格式:字符串、数字、布尔值、对象、数组。
渲染层可以通过WXML对数据进行绑定。
eg:
my.wxml
<view>{{text}}</view>
<view>{{array[0].msg}}</view>
my.js
Page({
/**
* 页面的初始数据
*/
data: {
text:'init data',
array:[{msg:'1'},{msg:'2'}]
},
...
})
3.事件处理函数
在渲染层可以在组件中加入事件绑定,当达到触发事件时,就会执行 Page 中定义的事件处理函数。
eg:
my.wxml
<view bindtap="viewTap"> click me </view>
my.js
Page({
viewTap:function(){
console.log('view tap')
}
})
3.1Page.prototype.route字段可以获取到当前页面的路径。
3.2Page.prototype.setData()
setData 函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)。
setData()参数格式
data - Object类型 - 必填 - 这次要改变的数据
callback - Function类型 - 非必填 - 回调函数
object 以 key,value 的形式表示将 this.data 中的 key 对应的值改变成 value;
其中 key 可以非常灵活,以数据路径的形式给出,如 array[2].message,a.b.c.d,并且不需要在 this.data 中预先定义。
callback 是一个回调函数,在这次setData对界面渲染完毕后调用。
注意:
1.直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
2.单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
3.请不要把 data 中任何一项的 value 设为 undefined ,否则这一项将不被设置并可能遗留一些潜在问题。
4.Page实例的生命周期
五、路由
在小程序中的所有页面的路由全部由框架进行管理。
1.页面栈
框架以栈的形式维护当前的所有页面。当发生路由切换时,页面栈的表现如下:
初始化 - 新页面入栈
打开新页面 - 新页面入栈
页面重定向 - 当前页面出栈,新页面入栈
页面返回 - 页面不断出栈,直到目标返回页,新页面入栈
Tab切换 - 页面全部出栈,只留下新的Tab页面
重加载 - 页面全部出栈,只留下新的页面
2.getCurrentPages()
getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
不要修改页面栈,会导致路由以及页面状态错误。
3.路由方式
对于路由的触发方式以及页面生命周期函数如下:
路由方式 | 触发时机 | 路由前页面 | 路由后页面 |
---|---|---|---|
初始化 | 小程序打开的第一个页面 | onLoad, onShow | |
打开新页面 | 调用 API wx.navigateTo 或使用组件 <navigator open-type=”navigateTo”/> | onHide | onLoad, onShow |
页面重定向 | 调用 API wx.redirectTo 或使用组件 <navigator open-type=”redirectTo”/> | onUnload | onLoad, onShow |
页面返回 | 调用 API wx.navigateBack 或使用组件 <navigator open-type=”navigateBack”<或用户按左上角返回按钮 | onUnload | onShow |
Tab切换 | 调用 API wx.switchTab 或使用组件 <navigator open-type=”switchTab”/< 或用户切换 Tab | 各种情况请参考下表 | |
重启动 | 调用 API wx.reLaunch 或使用组件<navigator open-type=”reLaunch”/> | onUnload | onLoad, onShow |
1.navigateTo, redirectTo 只能打开非 tabBar 页面。
2.switchTab 只能打开 tabBar 页面。
3.reLaunch 可以打开任意页面。
4.页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
5.调用页面路由带的参数可以在目标页面的onLoad中获取。
六、模块化
1.文件作用域
在 JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。
通过全局函数 getApp() 可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置,如:
// app.js
App({
globalData: 1
})
// a.js
// The localValue can only be used in file a.js.
var localValue = 'a'
// Get the app instance.
var app = getApp()
// Get the global data and change it.
app.globalData++
// b.js
// You can redefine localValue in file b.js, without interference with the localValue in a.js.
var localValue = 'b'
// If a.js it run before b.js, now the globalData shoule be 2.
console.log(getApp().globalData)
2.模块化
可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口。
exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造成未知的错误。
推荐开发者采用module.exports 来暴露模块接口,除非你已经清晰知道这两者的关系。
小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中。
// common.js
function sayHello(name) {
console.log(`Hello ${name} !`)
}
function sayGoodbye(name) {
console.log(`Goodbye ${name} !`)
}
module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye
在需要使用这些模块的文件中,使用 require(path) 将公共代码引入:
var common = require('common.js')//require 暂时不支持绝对路径
Page({
helloMINA: function() {
common.sayHello('MINA')
},
goodbyeMINA: function() {
common.sayGoodbye('MINA')
}
})
七、API
小程序开发框架提供丰富的微信原生 API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等。
参考资料:
1.框架 - 逻辑层
2.API 文档