在 UniApp 多端开发中,页面之间的数据传递与通信是绕不开的核心话题。无论是从列表页跳转到详情页,还是从表单页返回数据给上一页,都需要一套清晰可靠的传参方案。UniApp 提供了多种通信手段,每种都有其适用场景和边界。本文将系统梳理 URL 传参、EventChannel 以及全局状态三种主流方式,帮助你在实际项目中做出合理选择。
一、URL 传参:最基础也最常用
URL 传参是页面跳转时最直接的数据携带方式。通过 uni.navigateTo、uni.redirectTo、uni.switchTab 等 API 的 url 字段,可以在路径后拼接查询字符串。
基本用法
uni.navigateTo({
url: '/pages/detail/detail?id=123&name=uniapp'
})
在目标页面的 onLoad 生命周期中接收参数:
onLoad(options) {
console.log(options.id) // '123'
console.log(options.name) // 'uniapp'
}
传递复杂对象
URL 只能传递字符串,若需传递对象或数组,需要先序列化:
const params = { id: 1, tags: ['a', 'b'] }
uni.navigateTo({
url: `/pages/detail/detail?data=${encodeURIComponent(JSON.stringify(params))}`
})
接收时再反序列化:
onLoad(options) {
const data = JSON.parse(decodeURIComponent(options.data))
}
注意事项
- 长度限制:不同平台对 URL 长度有不同限制,过长的参数可能导致跳转失败,尤其是微信小程序对 URL 长度较为敏感。
- 特殊字符:参数值必须使用
encodeURIComponent编码,否则&、=、#等字符会破坏 URL 结构。 - 页面栈限制:
navigateTo最多保留十层页面栈,超出后需改用redirectTo。 - tabBar 页面:
switchTab不支持 URL 传参,跳转到 tabBar 页面时参数会被忽略。
URL 传参适合数据量小、结构简单的场景,比如传递一个 ID 或少量筛选条件。当数据量较大或结构复杂时,应优先考虑其他方案。
二、EventChannel:页面间的事件通道
EventChannel 是 UniApp 提供的一种页面间通信机制,它允许打开新页面时建立一条事件通道,实现双向通信。与 URL 传参的单向传递不同,EventChannel 可以让被打开页面主动向打开者发送数据,非常适合“选择后回传”的场景。
基本用法
在打开页面时,通过 events 字段监听事件:
uni.navigateTo({
url: '/pages/select/select',
events: {
// 监听被打开页面触发的事件
selectResult(data) {
console.log('收到回传数据:', data)
}
},
success(res) {
// 通过 eventChannel 向被打开页面发送数据
res.eventChannel.emit('initData', { from: 'list' })
}
})
在被打开页面中,通过 getOpenerEventChannel 获取通道:
onLoad() {
const eventChannel = this.getOpenerEventChannel()
// 接收打开者发送的数据
eventChannel.on('initData', (data) => {
console.log(data) // { from: 'list' }
})
// 向打开者回传数据
eventChannel.emit('selectResult', { id: 1, name: '选项A' })
}
适用场景
EventChannel 最典型的应用是“选择器”模式:A 页面打开 B 页面进行选择,B 页面选择完成后将结果回传给 A 页面。相比全局状态或缓存,EventChannel 的通信关系更加明确,代码可读性更强,也不会污染全局数据。
注意事项
- EventChannel 仅在
navigateTo打开的页面间有效,redirectTo、switchTab等不支持。 - 事件监听需要在页面销毁时注意清理,避免内存泄漏。
- 部分低版本平台对 EventChannel 支持不完整,使用前需确认目标平台兼容性。
三、全局状态:跨页面共享数据
当多个页面需要共享同一份数据,或者数据需要在页面栈之外持久存在时,全局状态是更合适的选择。UniApp 中常见的全局状态方案包括 Vuex、Pinia 以及简单的 globalData。
globalData
在 App.vue 中定义全局数据:
// App.vue
export default {
globalData: {
userInfo: null,
token: ''
}
}
在任意页面中读写:
const app = getApp()
app.globalData.token = 'abc123'
console.log(app.globalData.token)
globalData 简单直接,适合存放用户信息、配置项等全局共享数据。但它不具备响应式能力,数据变化不会自动触发页面更新。
Vuex / Pinia
对于需要响应式的复杂状态,推荐使用 Vuex 或 Pinia。以 Pinia 为例:
// stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
token: '',
userInfo: null
}),
actions: {
setToken(token) {
this.token = token
}
}
})
在页面中使用:
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
userStore.setToken('abc123')
console.log(userStore.token) // 响应式更新
适用场景对比
| 方案 | 响应式 | 持久化 | 适用场景 |
|---|---|---|---|
| globalData | 否 | 否 | 简单全局配置、用户信息 |
| Vuex/Pinia | 是 | 否 | 复杂状态管理、跨组件共享 |
| 本地存储 | 否 | 是 | 需要持久化的数据 |
全局状态的优势在于数据共享范围广、访问方便,但滥用会导致数据流向不清晰,难以追踪修改来源。建议只将真正需要全局共享的数据放入全局状态,页面间的临时传参仍优先使用 URL 或 EventChannel。
四、如何选择:三种方案的决策路径
面对具体场景,可以按以下思路快速决策:
- 数据量小且单向传递:优先使用 URL 传参,简单直接。
- 需要被打开页面回传数据:使用 EventChannel,通信关系清晰。
- 多个页面共享同一份数据:使用全局状态(Pinia/Vuex 或 globalData)。
- 数据需要持久化:结合
uni.setStorageSync等本地存储方案。
实际项目中,这三种方式往往混合使用。例如,用户登录后 token 存入全局状态,列表页跳转详情页时通过 URL 传递 ID,详情页中选择地址后通过 EventChannel 回传给表单页。理解每种方案的边界,才能写出清晰可维护的页面通信代码。
总结
UniApp 的页面传参与通信没有银弹,URL 传参、EventChannel 和全局状态各有其最佳适用场景。URL 传参胜在简单,适合轻量单向数据;EventChannel 解决了页面回传的痛点,让父子页面通信更加优雅;全局状态则负责跨页面的数据共享与响应式更新。在实际开发中,根据数据流向、数据量和共享范围灵活组合,才能构建出高效可靠的页面通信体系。
未经允许不得转载:任鹏个人博客 » UniApp 页面传参与通信:URL 传参、EventChannel 与全局状态


朋友圈点赞图在线生成源码