支付宝小程序框架 页面·运行机制
Page(object: Object)
在 /pages
目录的 .js 文件中,定义 Page()
,用于注册一个小程序页面,接受一个 object 作为属性,用来指定页面的初始数据、生命周期回调、事件处理等。
以下为一个基本的页面代码:
// pages/index/index.js
Page({
data: {
title: "Alipay",
},
onLoad(query) {
// 页面加载
},
onShow() {
// 页面显示
},
onReady() {
// 页面加载完成
},
onHide() {
// 页面隐藏
},
onUnload() {
// 页面被关闭
},
onTitleClick() {
// 标题被点击
},
onPullDownRefresh() {
// 页面被下拉
},
onReachBottom() {
// 页面被拉到底部
},
onShareAppMessage() {
// 返回自定义分享信息
},
// 事件处理函数对象
events: {
onBack() {
console.log('onBack');
},
},
// 自定义事件处理函数
viewTap() {
this.setData({
text: 'Set data for update.',
});
},
// 自定义事件处理函数
go() {
// 带参数的跳转,从 page/ui/index 的 onLoad 函数的 query 中读取 type
my.navigateTo({url:'/page/ui/index?type=mini'});
},
// 自定义数据对象
customData: {
name: 'alipay',
},
});
页面生命周期
下图说明了页面 Page 对象的生命周期。
小程序主要靠视图线程(Webview)和应用服务线程(Worker)来控制管理。视图线程和应用服务线程同时运行。
- 应用服务线程启动后运行 app.onLauch 和 app.onShow 以完成 App 创建,再运行 page.onLoad 和 page.onShow 以完成 Page 创建,此时等待视图线程初始化完成通知。
- 视图线程初始化完成通知应用服务线程,应用服务线程将初始化数据发送给视图线程进行渲染,此时视图线程完成第一次数据渲染。
- 第一次渲染完成后视图线程进入就绪状态并通知应用服务线程,应用服务线程调用 page.onReady 函数并进入活动状态。
- 应用线程进入活动状态后每次数据修改将会通知视图线程进行渲染。当切换页面进入后台,应用线程调用page.onHide 函数后,进入存活状态;页面返回到前台将调用 page.onShow 函数,进入活动状态;当调用返回或重定向页面后将调用 page.onUnload 函数,进行页面销毁。
object 属性说明
属性 | 类型 | 描述 | 最低版本 | |
---|---|---|---|---|
data | Object | Function | 初始数据或返回初始化数据的函数。 | - | |
events | Object | 事件处理函数对象 | 1.13.7 | |
onLoad | Function(query: Object) | 页面加载时触发 | - | |
onShow | Function | 页面显示时触发 | - | |
onReady | Function | 页面初次渲染完成时触发 | - | |
onHide | Function | 页面隐藏时触发 | - | |
onUnload | Function | 页面卸载时触发 | - | |
onShareAppMessage | Function(options: Object) | 点击右上角分享时触发 | - | |
onTitleClick | Function | 点击标题触发 | - | |
onOptionMenuClick | Function | 点击导航栏额外图标触发,设置额外图标 | 1.3.0 | |
onPopMenuClick | Function | 点击右上角通用菜单中的自定义菜单按钮触发 | 1.3.0 | |
onPullDownRefresh | Function({from: manual |
code }) |
页面下拉时触发 | - |
onPullIntercept | Function | 下拉中断时触发 | 1.11.0 | |
onTabItemTap | Function | 点击tabItem 时触发 |
1.11.0 | |
onPageScroll | Function({scrollTop}) | 页面滚动时触发 | - | |
onReachBottom | Function | 上拉触底时触发 | - | |
其他 | Any | 开发者可以添加任意的函数或属性到 object 中,在页面的函数中可以用 this 来访问 |
- |
页面数据对象 data
通过设置 data
指定页面的初始数据。当 data
为对象时,被所有页面共享。 即:当该页面回退后再次进入该页面时,会显示上次页面的数据,而非初始数据。这种情况,可以通过设置 data
为不可变数据或者变更 data
为页面独有数据两种方式来解决。
设置为不可变数据
Page({
data: { arr:[] },
doIt() {
this.setData({arr: [...this.data.arr, 1]});
},
});
设置页面独有数据(不推荐修改数据)
Page({
data() { return { arr:[] }; },
doIt() {
this.setData({arr: [1, 2, 3]});
},
});
注意:不要直接修改 this.data
,无法改变页面的状态,还会造成数据不一致。
比如:
Page({
data: { arr:[] },
doIt() {
this.data.arr.push(1); // 不要这么写!
this.setData({arr: this.data.arr});
}
});
生命周期函数
onLoad(query: Object)
页面初始化时触发。一个页面只会调用一次。 query 为 my.navigateTo
和 my.redirectTo
中传递的 query 对象。 query 内容格式为:“参数名=参数值&参数名=参数值…”。
属性 | 类型 | 描述 |
---|---|---|
query | Object | 打开当前页面路径中的参数 |
onShow()
页面显示/切入前台时触发。
onReady()
页面初次渲染完成时触发。 一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。 对界面的设置,如 my.setNavigationBar
请在 onReady
之后设置。
onHide()
页面隐藏/切入后台时触发。 如 my.navigateTo
到其他页面或底部 tab 切换等。
onUnload()
页面卸载时触发。 如 my.redirectTo
或 my.navigateBack
到其他页面等。
页面事件处理函数
onShareAppMessage(options: Object)
在 Page 中定义 onShareAppMessage 函数,设置该页面的分享信息。
- 每个 Page 页面的右上角菜单中默认有 分享 按钮;onShareAppMessage 函数只自定义分享的内容,不影响分享功能。
- 用户点击分享按钮的时候会调用。
- 此事件需要返回一个对象(Object)类型,用于自定义分享内容。
- 分享图片中的二维码的有效期为 60 天,若需要长期有效的二维码,请到 开发者后台 > 码管理 中生成。
- 小程序在 1.1.0+ 版本中开始支持 open-type 为 share 的按钮触发分享。
效果实例
示例代码
// API-DEMO page/API/share/share.json
{
"defaultTitle" : "onShareAppMessage"
}
<view class = "page" >
<view class = "page-description" > 点击右上角开始自定义分享 </view>
</view>
// API-DEMO page/API/share/share.js
Page ({
onShareAppMessage () {
return {
title : '分享 View 组件' ,
desc : 'View 组件很通用' ,
path : 'page/component/view/view' ,
};
},
});
按钮触发分享方式参考代码:
<view>
<button type="primary" open-type="share" a:if="{{canIUseShareButton}}">推荐给朋友</button>
</view>
Page({
data: { canIUseShareButton: true },
setShareButtonSwitch () { this.setData({ canIUseShareButton: my.canIUse('button.open-type.share') }) },
onLoad() { this.setShareButtonSwitch(); } ,
onShareAppMessage() {
return {
title: '小程序示例',
desc: '小程序官方示例Demo,展示已支持的接口能力及组件。',
path: 'page/component/component-pages/view/view?param=123'
}
}
});
入参是 Object 类型,属性如下:
属性 | 类型 | 说明 | 最低版本 |
---|---|---|---|
from | String | 触发来源: button:页面分享按钮触发 menu:右上角分享按钮触发 code:执行 my.showSharePanel 触发 | 1.10.0 |
target | Object | 如果 from 值为 button,则 target 为触发这次分享的 button,否则为 undefined。 | 1.10.0 |
webViewUrl | String | 页面中包含 web-view 组件时,返回当前 web-view 的URL。 | 1.6.0 |
onShareAppMessage 执行后必须返回一个分享对象,用于自定义分享内容。
返回值
属性 | 类型 | 必填 | 描述 | 最低版本 |
---|---|---|---|---|
title | String | 是 | 自定义分享标题。 | - |
desc | String | 否 | 自定义分享描述:由于分享到微博只支持最大长度 140 个字,因此建议长度不要超过该限制。 | - |
path | String | 是 | 自定义分享页面的路径,path中的自定义参数可在小程序生命周期的 onLoad方法中获取(参数传递遵循 http get 的传参规则)。path 路径里不能带根目录 / 。 | - |
content | String | 否 | 自定义吱口令文案,最多 28 个字符。 | 1.7.0 |
imageUrl | String | 否 | 自定义分享小图 icon 元素,支持:网络图片路径;apFilePath 路径;相对路径。使用场景详见下方说明。 | 1.4.0 |
bgImgUrl | String | 否 | 自定义分享预览大图,建议尺寸750x825,支持:网络图片路径;apFilePath路径(客户端10.1.58版本开始支持);相对路径(客户端 10.1.58 版本开始支持)。使用场景详见下方说明。 | 1.9.0 |
searchTip | String | 否 | 生成分享截图的搜索引导,设置该参数后,会在分享图片中增加上支付宝搜“设置关键字”的内容,设置关键字不能超过5个字。 | - |
success | Function | 否 | 分享成功后回调。 | 1.4.0 |
fail | Function | 否 | 分享失败后回调。 | 1.4.0 |
success 回调函数
属性 | 类型 | 描述 |
---|---|---|
channelName | String | 分享所选择的渠道 |
shareResult | Boolean | 分享是否成功 |
onTitleClick()
点击标题时触发。
onOptionMenuClick()
点击导航栏额外图标触发,设置额外图标。
onPopMenuClick()
点击右上角通用菜单中的自定义菜单按钮触发。
onPullDownRefresh({from: manual
|code
})
下拉刷新时触发。 需要先在 app.json 的 window
选项中开启 pullRefresh
。当处理完数据刷新后,my.stopPullDownRefresh
可以停止当前页面的下拉刷新。
onPullIntercept()
下拉中断时触发。
onTabItemTap(object: Object)
点击 tabItem
时触发。
属性 | 类型 | 描述 |
---|---|---|
from | String | 点击来源 |
pagePath | String | 被点击 tabItem 的页面路径 |
text | String | 被点击 tabItem 的按钮文字 |
index | Number | 被点击 tabItem 的序号,从0开始 |
onPageScroll({scrollTop})
页面滚动时触发,scrollTop 为页面滚动距离。
onReachBottom()
上拉触底时触发。
onReachBottom()是在上拉触底时才会触发,如果页面已经在页面底部继续上拉是不会再次触发。
可以配合 my.pageScrollTo 向上滚动一点位置或者在底部增加数据等方式让页面不是处在底部位置达到可以连续上拉触发onReachBottom()的效果。
events
为了使代码更加简洁,提供了新的事件处理对象 events。 已有的页面处理事件函数跟直接在 page 实例上暴露的事件函数等价。
注意:
events
从基础库1.13.7
版本 开始支持。- 请正确区分页面事件函数与
events
内同名事件函数的基础库版本要求。
以下是 events 支持的事件函数列表:
事件 | 类型 | 描述 | 最低版本 |
---|---|---|---|
onBack | Function | 页面返回时触发 | 1.13.7 |
onKeyboardHeight | Function | 键盘高度变化时触发 | 1.13.7 |
onOptionMenuClick | Function | 点击导航栏额外图标触发,设置额外图标 | 1.13.7 |
onPopMenuClick | Function | 点击右上角通用菜单中的自定义菜单按钮触发 | 1.13.7 |
onPullIntercept | Function | 下拉截断时触发 | 1.13.7 |
onPullDownRefresh | Function({from: manual /code }) |
页面下拉时触发 | 1.13.7 |
onTitleClick | Function | 点击标题触发 | 1.13.7 |
onTabItemTap | Function | 点击非当前 tabItem 后触发 |
1.13.7 |
beforeTabItemTap | Function | 点击非当前 tabItem 前触发 |
1.13.7 |
onResize | Function({size: {windowWidth: number, windowHeight: number}}) | window尺寸改变时触发 | 1.16.0 |
示例代码:
// 特征检测
my.canIUse('page.events.onBack');
Page({
data: {
text: 'This is page data.'
},
onLoad(){
// 页面加载时触发
},
events:{
onBack(){
// 页面返回时触发
},
onKeyboardHeight(e){
// 键盘高度变化时触发
console.log('键盘高度:', e.height)
},
onOptionMenuClick(){
// 点击右上角菜单按钮触发
},
onPopMenuClick(e){
// 点击右上角通用菜单中的自定义菜单按钮触发
console.log('用户点击自定义菜单的索引', e.index)
console.log('用户点击自定义菜单的name', e.name)
console.log('用户点击自定义菜单的menuIconUrl', e.menuIconUrl)
},
onPullIntercept(){
// 下拉截断时触发
},
onPullDownRefresh(e){
// 页面下拉时触发。e.from的值是“code”表示startPullDownRefresh触发的事件;值是“manual”表示用户下拉触发的下拉事件
console.log('触发下拉刷新的类型', e.from)
my.stopPullDownRefresh()
},
onTitleClick(){
// 点击标题触发
},
onTabItemTap(e){
// e.from是点击且切换tabItem后触发,值是“user”表示用户点击触发的事件;值是“api”表示switchTab触发的事件
console.log('触发tab变化的类型', e.from)
console.log('点击的tab对应页面的路径', e.pagePath)
console.log('点击的tab的文字', e.text)
console.log('点击的tab的索引', e.index)
},
beforeTabItemTap(){
// 点击但切换tabItem前触发
},
onResize(e){
// window尺寸改变时触发
var {windowWidth, windowHeight} = e.size
console.log('改变后window的宽度', windowWidth)
console.log('改变后window的高度', windowHeight)
},
}
})
Page.prototype.setData(data: Object, callback: Function)
setData
会将数据从逻辑层发送到视图层,同时改变对应的 this.data
的值。
Object
以 key: value
的形式表示,将 this.data
中的 key
对应的值改变成 value
。其中 key
可以非常灵活,以数据路径的形式给出,如 array[2].message
、a.b.c.d
,可以不需要在 this.data
中预先定义。
使用过程中,需要注意以下几点:
- 直接修改
this.data
无效,无法改变页面的状态,还会造成数据不一致。 - 仅支持设置可 JSON 化的数据。
- 请尽量避免一次设置过多的数据。
- 请不要把 data 中任何一项的 value 设为 undefined ,否则这一项将不被设置并可能遗留一些潜在问题。
示例代码:
<view>{{text}}</view>
<button onTap="changeTitle"> Change normal data </button>
<view>{{array[0].text}}</view>
<button onTap="changeArray"> Change Array data </button>
<view>{{object.text}}</view>
<button onTap="changePlanetColor"> Change Object data </button>
<view>{{newField.text}}</view>
<button onTap="addNewKey"> Add new data </button>
<view>hello: {{name}}</view>
<button onTap="changeName"> Change name </button>
Page({
data: {
text: 'test',
array: [{text: 'a'}],
object: {
text: 'blue',
},
name: 'taobao',
},
changeTitle() {
// 错误!不要直接去修改 data 里的数据
// this.data.text = 'changed data'
// 正确
this.setData({
text: 'ha',
});
},
changeArray() {
// 可以直接使用数据路径来修改数据
this.setData({
'array[0].text': 'b',
});
},
changePlanetColor(){
this.setData({
'object.text': 'red',
});
},
addNewKey() {
this.setData({
'newField.text': 'c',
});
},
changeName() {
this.setData({
name: 'alipay',
}, () => { // 接受传递回调函数
console.log(this); // this 当前页面实例
this.setData({ name: this.data.name + ', ' + 'welcome!'});
});
},
});
参数说明
事件 | 类型 | 描述 | 最低版本 |
---|---|---|---|
data | Object | 待改变的数据 | - |
callback | Function | 回调函数,在页面渲染更新完成之后执行。 | 使用 my.canIUse('page.setData.callback') 做兼容性处理,详见 1.7.0。 |
Page.prototype.$spliceData(data: Object, callback: Function)
说明:$spliceData
自 1.7.2 之后才支持,可以使用 my.canIUse('page.$spliceData') 做兼容性处理,详见 兼容接口说明。
spliceData
同样用于将数据从逻辑层发送到视图层,但是相比于 setData
,在处理长列表的时候,其具有更高的性能。
Object
以 key: value
的形式表示,将 this.data
中的 key
对应的值改变成 value
。其中 key
可以非常灵活,以数据路径的形式给出,如 array[2].message
、a.b.c.d
,可以不需要在 this.data
中预先定义。value
为一个数组(格式:[start, deleteCount, ...items]), 数组的第一个元素为操作的起始位置,第二个元素为删除的元素的个数,剩余的元素均为插入的数据。对应 es5
中数组的 splice
方法。
示例代码:
<!-- pages/index/index.axml -->
<view class="spliceData">
<view a:for="{{a.b}}" key="{{item}}" style="border:1px solid red">
{{item}}
</view>
</view>
// pages/index/index.js
Page({
data: {
a: {
b: [1,2,3,4],
},
},
onLoad(){
this.$spliceData({ 'a.b': [1, 0, 5, 6] });
},
});
页面输出:
1
5
6
2
3
4
参数说明
事件 | 类型 | 描述 |
---|---|---|
data | Object | 待改变的数据 |
callback | Function | 回调函数,在页面渲染更新完成之后执行。 |
Page.prototype.$batchedUpdates(callback: Function)
批量更新数据。
说明$batchedUpdates
自 1.14.0 之后才支持,可以使用 my.canIUse('page.$batchedUpdates') 做兼容性处理,详见 兼容接口说明。
参数说明:
事件 | 类型 | 描述 |
---|---|---|
callback | Function | 在此回调函数中的数据操作会被批量更新。 |
下面是示例代码:
// pages/index/index.js
Page({
data: {
counter: 0,
},
plus() {
setTimeout(() => {
this.$batchedUpdates(() => {
this.setData({
counter: this.data.counter + 1,
});
this.setData({
counter: this.data.counter + 1,
});
});
}, 200);
},
});
<!-- pages/index/index.axml -->
<view>{{counter}}</view>
<button onTap="plus">+2</button>
- 本示例中每次点击按钮,页面的
counter
会加 2。 - 将
setData
放在 this.$batchedUpdates 中,这样尽管有多次setData
,但是却只有一次数据的传输。
Page.route
Page 路径,对应 app.json 中配置的路径值,类型为 String。这是一个只读属性。
Page({
onShow() {
// 对应 app.json 中配置的路径值
console.log(this.route)
}
})
更多建议: