微信小程序页面跳转和参数传递
目录
小程序有页面之分,所以存在页面栈,它的操作就像的浏览器的历史操作 push, back 那样,小程序也有类似的页面栈操作。
功能 | Web浏览器 | 小程序 |
---|---|---|
跳转新页面 | history.push | wx.navigateTo |
返回上一页 | history.back | wx.navigateBack |
当前页重定向 | history.replace | wx.redirectTo |
上方是页面间的基本操作。不过在具体的开发中,除了跳转,还要处理页面之间的传值。
带参初始化
小程序支持通过带参初始化页面,达到按业务需要自动完成一些动作的效果。
开发者工具指定编译参数:

自定义编译参数,会传递给首个页面
编译后,首个页面初始化后从 onLoad 周期获取到参数,然后自动完成一些页面操作:
onLoad 期间可能无法更新界面,需要等待 onShow 触发后才能操作,所以一般是把 query 暂存
Page({
onLoad(query) {
query; // { name: "luoyz" }
query.name; // luoyz
if (query.name === 'luoyz'){
console.log('抽到3星')
} else {
console.log('抽到5星')
}
}
})
带参跳转
以下是简单的页面传值例子,A页面带参跳转B页面,B页面可以在 onLoad 周期获取到参数:

A 带参跳转到 B
// A 页面
wx.navigateTo({
url: `/pages/b/b?name=luoyz`
})
// B 页面
Page({
onLoad (query) {
query.name // luoyz
}
})
带参回传
带参回传即 A 跳转到 B 后,B 处理完业务,把结果回传给 A。

A 跳 B;B 回传 A
比起带参跳转,带参回传的实现复杂得多,因为 navigateBack 接口不能带参数。不过网上也有很多可用的方法,在这里说一下我看得最多的解决方案:
回传数据写在 App 全局变量
页面 B 把回传值写在 App 全局变量里面,navigateBack 回到 A 会触发 A 的 onShow,所以在 onShow 中处理回传的数据。
A 页面 onShow 会触发2次:
① 页面初始化触发一次
② navigateBack 回来再触发一次
// App
App({
globalData: {}
})
// A 页面
Page({
onShow() {
const app = getApp()
app.globalData.surveyResult // 第一次 null,回传后为 true
},
onClick() {
wx.navigateTo({ url: '/pages/b/b' })
}
})
// B 页面
Page({
onClick() {
const app = getApp()
app.globalData.surveyResult = true
wx.navigateBack()
}
})
回调数据通过页面栈写在上一页的 data
这种方法是用小程序获取页面栈的接口 getCurrentPages()
获得当前页面栈。
getCurrentPages() // 页面对象数组 [A, B]
getCurrentPages()[getCurrentPages().length - 1] // 当前页面
在下面的例子,B 是从 A 跳转来的,那么 B 可以访问、修改上一页的页面属性,即 A。
和方法1一样,A 的 onShow 也会触发2次。初始化触发一次,从 B 返回时触发一次
// A 页面
Page({
data: {
surveyResult: null
},
onShow() {
this.data.surveyResult // 第一次 null,回传后为 true
},
onClick() {
wx.navigateTo({ url: '/pages/b/b' })
}
})
// B 页面
Page({
onClick() {
// A 跳转到 B,则页面栈 = [A, B]
const currentPages = getCurrentPages()
const PageA = currentPages[0]
const PageB = currentPages[1]
PageA.setData({ surveyResult: true })
wx.navigateBack()
}
})
NavigationChannel 跳转库
上方的跳转和回传处理,是在网上找到的比较常见的小程序跳转解决方案。
页面参数传递的过程比较像事件流,不管是初始化,还是跳转、回传,都需要 onLoad、onShow 触发(只有在触发时候,业务操作才有效果)。
我之前写的一篇文章 ❐ 速览: 基于事件实现流程控制 做了个流程控制工具 PromisifyChannel,可以把事件流转换成业务回调。最近趁着业务需要,我试着把 PromisifyChannel 搬到小程序的上,实现小程序页面的跳转和传参。
NavigationChannel 是用于小程序页面跳转工具库,可以将 onLoad、onShow 的事件转换为业务流程。
每个页面都要配置 NavigationChannel 才能实现页面之间的跳转
注入 NavigationChannel
Page({
...withNavigationChannel()
})
NavigationChannel 接管生命周期
onLoad(query) {
this.initNavigationChannel({...}) // 初始化
this.getNavigationChannel().handleOnLoad(query)
}
onShow() {
this.getNavigationChannel().handleOnShow()
}
NavigationChannel 初始化
NavigationChannel 必须在 onLoad 期间初始化,初始化完了后,调用 handleOnLoad(query)
接管 onLoad 的参数。
NavigationChannel 自动获取当前页面的路由。
// 页面 A
this.initNavigationChannel({
handleCmdFunc: (key, cmd) => {
cmd.fn; // 调用方法名
cmd.fromPageRoute; // 发起请求的页面
cmd.targetPageRoute; // 跳转的目标页面
cmd.encoding; // 编码方式,如果 data 是对象,则应该用 jsonbase64,默认纯文本
cmd.data; // 调用参数
},
})
// 页面 B
this.initNavigationChannel({
handleCmdFunc: (key, cmd) => {
const channel = this.getNavigationChannel()
// 发送回传
// channel.sendRsp(key, {
// fromPageRoute: cmd.fromPageRoute,
// targetPageRoute: cmd.targetPageRoute,
// encoding: 'plain',
// data: 'bdata',
// })
// 发送回传,自动填写发送者信息
channel.sendRspWithCmd(key, cmd, {
encoding: 'plain',
data: 'bdata',
})
}
})
NavigationChannel 带参跳转
// A 带参 luoyz 跳转 B
this.getNavigationChannel().invoke({
targetPageRoute: '/pages/b/b', // pages/b/b 也可,会补斜杠
fn: '开始验证',
data: 'luoyz'
}).then(rsp => {
rsp.data // = bdata
})
NavigationChannel 处理编译参数
让 NavigationChannel 处理小程序首个页面的编译参数,此时 fromPageRoute、targetPageRoute 为空。
// 编译参数: fn=setname&data=luoyz
this.initNavigationChannel({
handleCmdFunc: (key, cmd) => {
cmd.fn; // setname
cmd.data; // luoyz
}
})