UniApp 页面传参与通信:URL 传参、EventChannel 与全局状态

在 UniApp 多端开发中,页面之间的数据传递与通信是绕不开的核心话题。无论是从列表页跳转到详情页,还是从表单页返回数据给上一页,都需要一套清晰可靠的传参方案。UniApp 提供了多种通信手段,每种都有其适用场景和边界。本文将系统梳理 URL 传参、EventChannel 以及全局状态三种主流方式,帮助你在实际项目中做出合理选择。

一、URL 传参:最基础也最常用

URL 传参是页面跳转时最直接的数据携带方式。通过 uni.navigateTouni.redirectTouni.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 打开的页面间有效,redirectToswitchTab 等不支持。
  • 事件监听需要在页面销毁时注意清理,避免内存泄漏。
  • 部分低版本平台对 EventChannel 支持不完整,使用前需确认目标平台兼容性。

三、全局状态:跨页面共享数据

当多个页面需要共享同一份数据,或者数据需要在页面栈之外持久存在时,全局状态是更合适的选择。UniApp 中常见的全局状态方案包括 VuexPinia 以及简单的 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。

四、如何选择:三种方案的决策路径

面对具体场景,可以按以下思路快速决策:

  1. 数据量小且单向传递:优先使用 URL 传参,简单直接。
  2. 需要被打开页面回传数据:使用 EventChannel,通信关系清晰。
  3. 多个页面共享同一份数据:使用全局状态(Pinia/Vuex 或 globalData)。
  4. 数据需要持久化:结合 uni.setStorageSync 等本地存储方案。

实际项目中,这三种方式往往混合使用。例如,用户登录后 token 存入全局状态,列表页跳转详情页时通过 URL 传递 ID,详情页中选择地址后通过 EventChannel 回传给表单页。理解每种方案的边界,才能写出清晰可维护的页面通信代码。

总结

UniApp 的页面传参与通信没有银弹,URL 传参、EventChannel 和全局状态各有其最佳适用场景。URL 传参胜在简单,适合轻量单向数据;EventChannel 解决了页面回传的痛点,让父子页面通信更加优雅;全局状态则负责跨页面的数据共享与响应式更新。在实际开发中,根据数据流向、数据量和共享范围灵活组合,才能构建出高效可靠的页面通信体系。

未经允许不得转载:任鹏个人博客 » UniApp 页面传参与通信:URL 传参、EventChannel 与全局状态

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏