uni-app 中页面传参有哪些方式?各自适用什么场景?

在 uni-app 开发中,页面传参是日常开发里非常高频的操作。无论是列表跳详情、表单回填,还是跨页面通信,都离不开参数传递。面试中,这道题往往不只是考察“你会不会用”,而是看你是否理解不同传参方式的底层机制、适用边界以及各自的坑。下面从实际开发视角,系统梳理 uni-app 中常见的页面传参方式。

一、URL 查询字符串传参

这是最基础、最常用的方式,本质上和传统 Web 的 ?key=value 一致。

使用方式:

// 传递
uni.navigateTo({
  url: '/pages/detail/detail?id=123&name=uniapp'
})

// 接收
onLoad(options) {
  console.log(options.id)   // '123'
  console.log(options.name) // 'uniapp'
}

适用场景:

  • 列表页跳转到详情页,传递商品 ID、文章 ID 等简单标识
  • 页面间传递少量、简单的字符串或数字参数
  • 需要分享链接或复制链接时,参数能直接体现在 URL 中

注意事项:

  • 参数值必须进行 encodeURIComponent 编码,否则遇到特殊字符(如 &=、中文)会解析错误
  • 传递对象或数组时,需要先 JSON.stringify,接收后再 JSON.parse
  • URL 长度有限制,参数过多或过大时不适合
  • 参数会暴露在地址栏中,敏感信息不应通过此方式传递

编码示例:

const params = encodeURIComponent(JSON.stringify({ id: 1, list: [1,2] }))
uni.navigateTo({ url: `/pages/detail/detail?data=${params}` })

// 接收
onLoad(options) {
  const data = JSON.parse(decodeURIComponent(options.data))
}

二、eventChannel 事件通道传参

eventChannel 是 uni-app 提供的一种页面间通信机制,适用于需要双向通信或传递复杂数据的场景。

使用方式:

// 页面 A:跳转并监听
uni.navigateTo({
  url: '/pages/detail/detail',
  success: (res) => {
    res.eventChannel.emit('sendData', { id: 1, name: 'uniapp' })
  }
})

// 页面 B:接收
onLoad() {
  const eventChannel = this.getOpenerEventChannel()
  eventChannel.on('sendData', (data) => {
    console.log(data)
  })
}

适用场景:

  • 需要传递对象、数组等复杂数据结构,且不想手动序列化
  • 子页面需要向父页面回传数据(如选择地址后返回)
  • 页面间需要多次通信,而非一次性传参

注意事项:

  • 只能通过 navigateTo 打开页面时使用,redirectToswitchTab 不支持
  • 页面 B 必须是通过 navigateTo 打开的,否则 getOpenerEventChannel 获取不到
  • 事件通道是单向的,父页面监听子页面 emit 的事件需要额外处理

回传数据示例:

// 页面 B 回传
const eventChannel = this.getOpenerEventChannel()
eventChannel.emit('backData', { address: '北京市' })

// 页面 A 监听
uni.navigateTo({
  url: '/pages/address/address',
  events: {
    backData: (data) => {
      console.log(data.address)
    }
  }
})

三、全局变量 / 全局状态管理传参

通过 getApp().globalData 或 Vuex / Pinia 等状态管理工具,在全局共享数据。

使用方式:

// main.js 或 App.vue 中定义
globalData: {
  userInfo: null
}

// 页面 A:赋值
getApp().globalData.userInfo = { name: 'uniapp' }

// 页面 B:读取
const userInfo = getApp().globalData.userInfo

适用场景:

  • 多个页面都需要使用的数据,如用户登录信息、主题配置
  • 参数数据量大,不适合放在 URL 中
  • 跨页面、跨层级的复杂状态共享

注意事项:

  • 全局变量是响应式的吗?globalData 本身不是响应式的,需要配合 Vuex/Pinia 才能实现响应式更新
  • 数据不会自动清理,页面销毁后仍存在,需手动管理
  • 不适合临时性、一次性的传参,容易造成数据污染

四、本地存储传参

通过 uni.setStorageSync / uni.getStorageSync 在本地缓存中存取数据。

使用方式:

// 页面 A:存储
uni.setStorageSync('tempData', { id: 1, name: 'uniapp' })

// 页面 B:读取
const data = uni.getStorageSync('tempData')
uni.removeStorageSync('tempData') // 用完清理

适用场景:

  • 需要持久化保存的数据,如草稿、历史记录
  • 参数较大,URL 无法承载
  • 页面刷新或应用重启后仍需保留的数据

注意事项:

  • 存储有容量限制(通常 10MB 左右)
  • 同步操作可能阻塞主线程,大数据量建议用异步 API
  • 需要手动清理,否则会造成缓存堆积

五、Vuex / Pinia 状态管理传参

在 uni-app 中使用 Vuex 或 Pinia,通过 store 共享状态。

使用方式:

// store 中定义
state: { orderInfo: {} }
mutations: { setOrderInfo(state, payload) { state.orderInfo = payload } }

// 页面 A
this.$store.commit('setOrderInfo', { id: 1 })

// 页面 B
this.$store.state.orderInfo

适用场景:

  • 中大型项目中多个页面共享复杂状态
  • 需要响应式更新、派生状态、模块化管理
  • 参数需要在多个页面间保持同步

注意事项:

  • 需要引入并配置 Vuex/Pinia,有一定学习成本
  • 状态在页面刷新后会丢失(除非配合持久化插件)
  • 不适合简单的临时传参,容易过度设计

六、各方式对比与选型建议

传参方式 数据量 复杂度 生命周期 适用场景
URL 查询字符串 简单 页面级 列表跳详情、简单标识
eventChannel 中等 页面级 复杂对象、双向通信
全局变量 简单 应用级 用户信息、全局配置
本地存储 简单 持久化 草稿、历史记录
Vuex/Pinia 复杂 应用级 中大型项目状态共享

选型原则:

  1. 简单优先:能用 URL 传参就用 URL,不要过度设计
  2. 数据量决定方式:小数据用 URL,大数据用全局或存储
  3. 生命周期决定方式:临时数据用 eventChannel,持久数据用存储
  4. 项目规模决定方式:小型项目用 globalData,中大型项目用 Vuex/Pinia

七、面试加分点

回答这道题时,如果能补充以下内容,会显得更有深度:

  • URL 传参的编码问题:为什么需要 encodeURIComponent,不编码会怎样
  • eventChannel 的局限性:为什么 redirectTo 不能用,底层原理是什么
  • globalData 的非响应式问题:如何配合 Vuex 实现响应式
  • 各端的差异:小程序端 URL 长度限制、本地存储容量限制等
  • 实际踩坑经验:如 URL 传对象时 JSON.stringify 后仍可能因特殊字符出错

总结

uni-app 页面传参没有“万能方案”,关键是理解每种方式的机制和边界。URL 传参适合简单场景,eventChannel 适合复杂对象和双向通信,全局变量和状态管理适合跨页面共享,本地存储适合持久化。实际开发中,往往是多种方式组合使用。面试时,除了列出方式,更要讲清楚“为什么选它”和“什么时候不选它”,这才是区分初级和高级开发者的关键。

未经允许不得转载:任鹏个人博客 » uni-app 中页面传参有哪些方式?各自适用什么场景?

赞 (0) 打赏

评论 0

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

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

支付宝扫一扫打赏

微信扫一扫打赏