一、小程序框架结构
小程序框架分场景获取、逻辑层和视图层
- 场景获取:场景值是用来描述用户进入小程序的路径,可以在小程序的生命周期
onLaunch
或onShow
里获取。也可以通过wx.getLaunchOptionsSync来获取场景值。详细的场景列表可以在下面文档查看。
- 逻辑层:先要知道小程序开发框架的逻辑层是基于js引擎来给开发者提供代码运行环境和小程序里特有的功能;逻辑层的意义在于处理数据发送给视图层,进行数据状态变化,同时逻辑层也接受视图层的事件反馈。
还有一点需要注意,就是小程序的逻辑层不运行在浏览器,所以一些web的一些能力无法使用,比如document、window之类的。在js基础上,小程序又新增了一些功能方法,方便开发
1. 增加App
和Page
方法,进行程序注册和页面注册。
2. 增加getApp
和getCurrentPages
方法,分别用来获取App
实例和当前页面栈。
3. 提供丰富的 API,如微信用户数据,扫一扫,支付等微信特有能力。
4. 提供模块化能力,每个页面有独立的作用域逻辑层:注册小程序(小程序创建的时候这边已经注册和绑定,如果项目中不需要特殊处理,不需要改动)
每个小程序开始需要在app.js里注册和挂在小程序的实例,绑定生命周期回调函数、错误监听和页面不存在监听函数等。整个小程序只能存在一个APP实例,我们可以通过getApp
方法获取到全局唯一的 App 实例,获取App上的数据或调用开发者注册在App
上的函数。文档参考:
逻辑层:注册页面。
对于小程序中的每个页面,都需要在页面对应的js
文件中进行注册,指定页面的初始数据、生命周期回调、事件处理函数等。
简单页面直接用Page来注册页面
Page({data: {text: "This is page data."},onLoad: function(options) {// 页面创建时执行},onShow: function() {// 页面出现在前台时执行},onReady: function() {// 页面首次渲染完毕时执行},onHide: function() {// 页面从前台变为后台时执行},onUnload: function() {// 页面销毁时执行},onPullDownRefresh: function() {// 触发下拉刷新时执行},onReachBottom: function() {// 页面触底时执行},onShareAppMessage: function () {// 页面被用户分享时执行},onPageScroll: function() {// 页面滚动时执行},onResize: function() {// 页面尺寸变化时执行},onTabItemTap(item) {// tab 点击时执行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'}
})
如果页面比较负责,则需要使用 Component 构造器构造页面,这个就类似VUE,方法都放在methods里。
Component({data: {text: "This is page data."},methods: {onLoad: function(options) {// 页面创建时执行},onPullDownRefresh: function() {// 下拉刷新时执行},// 事件响应函数viewTap: function() {// ...}}
})
在页面中引用behaviors,可以做到多个页面同时共有相同的数据和方法。
// my-behavior.js
module.exports = Behavior({data: {sharedText: 'This is a piece of data shared between pages.'},methods: {sharedMethod: function() {this.data.sharedText === 'This is a piece of data shared between pages.'}}
})
// page-a.js
var myBehavior = require('./my-behavior.js')
Page({behaviors: [myBehavior],onLoad: function() {this.data.sharedText === 'This is a piece of data shared between pages.'}
})
逻辑层:生命周期 page实例的生命周期(现在看懂有点难,后面慢慢理解)
逻辑层:页面路由 小程序中所有页面的路由全部由框架进行管理。
页面栈
框架以栈的形式维护了当前的所有页面。 当发生路由切换的时候,页面栈的表现如下:
路由方式页面栈表现初始化新页面入栈打开新页面新页面入栈页面重定向当前页面出栈,新页面入栈页面返回页面不断出栈,直到目标返回页Tab 切换页面全部出栈,只留下新的 Tab 页面重加载页面全部出栈,只留下新的页面
开发者可以使用 getCurrentPages()
函数获取当前页面栈。
路由方式
对于路由的触发方式以及页面生命周期函数如下:
路由方式触发时机路由前页面路由后页面初始化小程序打开的第一个页面onLoad, onShow打开新页面调用 API wx.navigateTo
使用组件 <navigator open-type="navigateTo"/>
onHideonLoad, onShow页面重定向调用 API wx.redirectTo
使用组件 <navigator open-type="redirectTo"/>
onUnloadonLoad, onShow页面返回调用 API wx.navigateBack
使用组件<navigator open-type="navigateBack">
用户按左上角返回按钮onUnloadonShowTab 切换调用 API wx.switchTab
使用组件 <navigator open-type="switchTab"/>
用户切换 Tab各种情况请参考下表重启动调用 API wx.reLaunch
使用组件 <navigator open-type="reLaunch"/>
onUnloadonLoad, onShow
Tab 切换对应的生命周期(以 A、B 页面为 Tabbar 页面,C 是从 A 页面打开的页面,D 页面是从 C 页面打开的页面为例):
当前页面路由后页面触发的生命周期(按顺序)AANothing happendABA.onHide(), B.onLoad(), B.onShow()AB(再次打开)A.onHide(), B.onShow()CAC.onUnload(), A.onShow()CBC.onUnload(), B.onLoad(), B.onShow()DBD.onUnload(), C.onUnload(), B.onLoad(), B.onShow()D(从转发进入)AD.onUnload(), A.onLoad(), A.onShow()D(从转发进入)BD.onUnload(), B.onLoad(), B.onShow()
Tips:
navigateTo
,redirectTo
只能打开非 tabBar 页面。switchTab
只能打开 tabBar 页面。reLaunch
可以打开任意页面。- 页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
- 调用页面路由带的参数可以在目标页面的
onLoad
中获取。
逻辑层:模块化
可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过module.exports
或者exports
才能对外暴露接口。
// common.js
function sayHello(name) {console.log(`Hello ${name} !`)
}
function sayGoodbye(name) {console.log(`Goodbye ${name} !`)
}module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye
var common = require('common.js')
Page({helloMINA: function() {common.sayHello('MINA')},goodbyeMINA: function() {common.sayGoodbye('MINA')}
})
文件作用域
在 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)
逻辑层:API 后面会有详细提到。
- 视图层 View
基本解释:框架的视图层由 WXML 与 WXSS 编写,由组件来进行展示。
将逻辑层的数据反应成视图,同时将视图层的事件发送给逻辑层。
WXML(WeiXin Markup language) 用于描述页面的结构。
WXS(WeiXin Script) 是小程序的一套脚本语言,结合 WXML
,可以构建出页面的结构。
WXSS(WeiXin Style Sheet) 用于描述页面的样式。
组件(Component)是视图的基本组成单元。[1]
(视图层还有一些细节,想看的可以直接去看官方文档)
二、小程序运行环境
微信小程序运行在多种平台上:iOS(iPhone/iPad)微信客户端、Android 微信客户端、PC 微信客户端、Mac 微信客户端和用于调试的微信开发者工具。
JavaScript 支持情况
运行限制
基于安全考虑,小程序中不支持动态执行 JS 代码,即:
- 不支持使用
eval
执行 JS 代码 - 不支持使用
new Function
创建函数
有个函数支持表,可以去文档查看一下。我就不在这贴了。
小程序运行机制
前台/后台状态
小程序启动后,界面被展示给用户,此时小程序处于前台状态。
当用户点击右上角胶囊按钮关闭小程序,或者按了设备 Home 键离开微信时,小程序并没有完全终止运行,而是进入了后台状态,小程序还可以运行一小段时间。
当用户再次进入微信或再次打开小程序,小程序又会从后台进入前台。但如果用户很久没有再进入小程序,或者系统资源紧张,小程序可能被销毁,即完全终止运行。
小程序启动
这样,小程序启动可以分为两种情况,一种是冷启动,一种是热启动。
- 冷启动:如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序需要重新加载启动,即冷启动。
- 热启动:如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态,这个过程就是热启动。
小程序销毁时机
通常,只有当小程序进入后台一定时间,或者系统资源占用过高,才会被销毁。具体而言包括以下几种情形:
- 当小程序进入后台,可以维持一小段时间的运行状态,如果这段时间内都未进入前台,小程序会被销毁。
- 当小程序占用系统资源过高,可能会被系统销毁或被微信客户端主动回收。
- 在 iOS 上,当微信客户端在一定时间间隔内连续收到系统内存告警时,会根据一定的策略,主动销毁小程序,并提示用户 「运行内存不足,请重新打开该小程序」。具体策略会持续进行调整优化。
- 建议小程序在必要时使用 wx.onMemoryWarning 监听内存告警事件,进行必要的内存清理。
小程序更新机制
未启动时更新
开发者在管理后台发布新版本的小程序之后,如果某个用户本地有小程序的历史版本,此时打开的可能还是旧版本。微信客户端会有若干个时机去检查本地缓存的小程序有没有更新版本,如果有则会静默更新到新版本。总的来说,开发者在后台发布新版本之后,无法立刻影响到所有现网用户,但最差情况下,也在发布之后 24 小时之内下发新版本信息到用户。用户下次打开时会先更新最新版本再打开。
启动时更新
小程序每次冷启动时,都会检查是否有更新版本,如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。
(PS 这块的机制属于小程序运行时的机制,理解最好,不理解也能写。)[2]
参考
- ^项目写的时wxml基本html,不会过多记录,后面会着重讲wxs和component
- ^现在先过一下小程序的基本介绍和功能,以及结构理解。方便后面开发。先理解。