# 微信小程序-页面间如何进行传递数据(通信)

# 快速导航

# 前言

在小程序中组件与组件之间的通信是通过在引用组件处,在自定义组件上添加自定义属性实现的,子组件内部通过properties进行接收

更多关于组件与组件之间的通信可参考小程序实现自定义组件以及自定义组件间的通信这篇文章

那页面与页面之间又如何传递数据?

您将阅读完本文后,将收获到:

  1. 页面间跳转携带参数(通过url的方式)传递数据
  2. 如何返回上一级页面,并刷新页面呢
  3. 使用全局app页面定义的变量实现数据的传递
  4. 使用本地缓存数据
  5. 使用 eventChannel 向被打开页面传送数据(wx.navigateTo高级用法)

# 页面间通过 url 方式传递数据

在小程序中当中,在父页面,通过url方式传递参数到子页面,是一种比较常见的做法

如下示例所示:应用场景

  1. 点击列表页面,进入详情页
  2. 动态改变详情页面的navBar中的title
效果展示

点击图片扫码即可体验

# 父页面实例代码

切换tab选项就可以查看对应的代码,在上面示例中,从一个页面跳转到另一个页面是使用wx.navigateTo()这个方法,如果想要将该页面的数据传递到子页面中,可以通过url拼接参数的方式进行传递,多个参数之间使用&符号相连

路径后可以带参数,参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如path?key=value&key2=value2

上面示例代码中使用了es6的模板字符串,参数之间,也可以使用+拼接,个人觉得使用+真的很难受,不舒服,容易出错

# 子页面实例代码

当父页面通过url的方式传递数据给子页面时,在子页面中的生命周期onLoad函数中的options中可以拿到 想要更改什么数据,直接重新setData就可以了的

注意

  1. url的方式适合页面间跳转携带参数,多个参数之间使用&符号拼接
  2. 此方法有一定的局限性,不适宜传入复杂的数据,例如:数组,对象
  3. 适合参数比较少的情况

# url 中有多个参数时传递

在小程序中,向跳转的目标url页面传递的参数有时候远不止一个,使用wx.navigator进行跳转,支持/pages/xxx/xxx?param1=${param1}&param2=${param2}&param3=${param3}的方式,并不支持类似obj={key1:value1,key2: value2}对象或者数组list: [arr1, arr2, arr3 ..]

url参数是数组情况

url参数是对象情况

url参数是对象时,并不会像数组一样,在目标页面中onLoadoptions对象中是一个字符串,而却是一个对象

如下所示

{
  obj: [object, object];
}
1
2
3

我们需要借助JSON.stringify()对传入的参数对象进行序列化

那么在子页面中,需要通过JSON.parse()对父页面中传递过来的参数进行反序列化,否则拿到的将是字符串对象,是无法通过对象.的方式访问属性

# 可能会遇到的问题

当传递的对象数据中含有特殊字符串时,在下个页面使用JSON.parse()还原为对象时会报错 也就是当url传参 参数值过长,在子页面接收时,会出现问题,存在丢失情况

具体解决办法

在上个页面(被跳转页面)将对象转化为字符串后(JSON.stringify()),然后使用encodeURIComponent进行编码,然后在下个页面先用decodeURIComponent进行解码,最终在还原为对象

注意

  1. 当父页面传递的url参数为对象时,在子页面是无法直接获取的,在父页面中,必须先使用JSON.stringify()转换为字符串 然后在下个页面使用JSON.parse()还原为对象,这样在子页面中便可以通过对象的方式拿到

  2. 当父页面传递的url对象数据中含有特殊字符串时,在子页面使用 JSON.parse()还原为对象时会报错。需要在上个(父)页面将对象转化为字符串后(JSON.stringify()),在使用 encodeURIComponent 进行编码,然后在下个(子)页面先用 decodeURIComponent 进行解码在还原(JSON.parse())为对象。

# 如何返回上一级页面-并刷新页面

在使用wx.navigateTo()API 进行跳转时,在子页面中可以通过wx.navigateBack()返回上一级页面的

这个场景在日常开发中,就有不少的

例如:写完微博,发完微博成功后,自动要返回到首页,申请退款时,跳转到申清退款页面等等的

const pages = getCurrentPages(); // 可以获取当前页面栈,上一个页面以及当前页面栈信息
console.log(pages); // 是一个数组,记录了上一个页面与当前页面信息
// 取到上一个页面
const prevPage = pages[pages.length - 2]; // 获取第0个页面,也就是上个页面
console.log(prevPage);
prevPage.onLoad(); // 可以调用上一页面的方法
prevPage.setData({
  name: 'itclanCoder',
});
1
2
3
4
5
6
7
8
9

这个方法非常厉害,而且很有用,当你通过wx.navigateTo(),一层一层跳转到子页面时,使用getCurrentPages方法就可以找到上级,上上级的页面栈信息

它是通过获取到其他页面的原型对象,然后通过小程序原型下的setData方法,对当前对象管理的数据data进行修改

这个方法getCurrentPage方法可以操作页面堆栈页面的数据和方法,可以做到对子(后一)页面对父(上一)页面的数据管理

提示

getCurrentPages()用于获取当前页面栈,数组中第一个元素为首页,最后一个元素为当前页面

  1. 不要尝试修改页面栈,会导致路由以及页面状态错误(不要依赖这个方法)
  2. 不要在 App.onLaunch 的时候调用 getCurrentPages(),此时 page 还没有生成

# 使用全局app页面定义的变量实现数据的传递

在小程序当中,当有多个页面用到一些公共变量对象参数时,例如:小程序的openId,一些公用的状态,可以放到全局app

# 全局定义变量注意事项

  1. App()必须在app.js中注册,且不能注册多个
  2. 不要在定义App()内的函数调用getApp(),使用this就可以拿到App下的实例
  3. 不要在 App.onLaunch 的时候调用 getCurrentPages(),此时 page 还没有生成
  4. 通过getApp()获取到全局页面的实例后,就不要私自调用生命周期函数了的

# 使用本地缓存

在微信小程序都可以有自己的本地缓存

  • wx.setStorageSync:同步设置本地存储某个指定的key数据
  • wx.setStorage: 异步设置本地所有存储某个key数据
  • wx.getStorage: 异步获取本地所有存储数据
  • wx.getStorageSync:同步获取本地存储某个指定key的数据
  • wx.clearStorage:一次性清除所有本地存储(缓存)数据,不需要参数
  • wx.clearStorageSync:一次性清除同步所有本地存储,不需要参数
  • wx.removeStorage:从本地缓存中异步移除指定 key,需要指定某个key
  • wx.removeStorageSync:从本地存储中同步移除指定的key,需要指定某个key

上面的方法可以对本地缓存进行读写和清理的操作,读与写都是一一对应的

使用本地缓存,可以作为页面间数据传递,但是仍然需要注意一些实用情况,如下所示

注意事项

将数据存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容

也就是说,如果是相同的key,后面的会覆盖掉原来该 key 对应的内容

# 设置/获取/删除存储

使用的是wx.setStorageSync(),wx.getStorageSync方法

关于小程序中本地存储的方法确实容易让人晕,搞混淆,理解它们的区别,还是要在开发者工具中,自行调试,才知道每个方法之间区别差异的

光看文字,不动手写代码测试,是无法理解他们之间的差异的,很容易搞混,在使用时容易乱套

提示

凡是带sync结尾的都是同步的,而凡是带clear开头的都是一次性清除同步/异步的存储,而带·remove开头的都是需要指定删除某个存储的key

# 解决相同 key 覆盖问题

在小程序中,当出现同名key,后者key覆盖前者是一个让人头疼的问题

具体解决

可以将需要存储数据存到一个数组当中,当需要使用时,取最后一个即可

至于若有增删操作,每次删除完某一数据后,重新在设置一次本地存储即可

let lists = wx.getStorageSync('lists'); // 先获取lists本地存储的数据
if (!lists) {
  // 第一次判断缓存中有没有lists数据
  lists = []; // 若没有,则存储设置一个空数组
}
lists.push(data); // 这里的data是要存储到本地中的数据
wx.setStorageSync('lists', lists); // 设置本地存储key:val
1
2
3
4
5
6
7

通过上面的操作,就解决了存储 key 值覆盖的问题,那么如何取最新的呢

const storageList = wx.getStorageSync('lists');
const listData = storageList[storageList.length - 1]; // 获取到最后一个
this.setData({
  // 重新setData数据即可
  lists: listData,
});
1
2
3
4
5
6

# 是使用同步存储还是异步存储

带有Sync,这个表示的同步的操作,与之相对的不带后缀就是异步”。

同步与异步是指的消息通讯机制。就是信息传来传去的时候是同步还异步。重点强调的是通讯这个动作。

很容易混淆,在计算机里,他们两是对立,相反的,同步代码是顺序执行,会形成阻塞,而异步代码不会阻塞,它是等待主线程执行完后,可以在回过头来执行

比如要请求用户信息的时候,需要从缓存中获取username这个变量,那只有先获取到这个变量才能进行下一步。那就应该使用同步,使用wx.getStorageSync。这样能确保一定能获取到这个变量,所有在第一次获取缓存中的数据时

我们往往先要判断一下缓存中是否有我们想要的那一数据的,否则若没有,在代码中使用了,就会报错

打电话就是一个同步的例子,必须先打完上一个,然后才能在打下一个,而发短信就是一个异步的例子,你可以跟 A 同学发,发完后不用等待,也可以更 B 同学发

在相同的时间内,使用同步只能干一件事情,必须得一件,一件的干完,而异步则在同一段时间内,可以同时干多件事情

JavaScript 是单线程的,但是浏览器是多线程的.它的异步是借助事件实现的.具体可自行查看多线程与单线程相关知识的

# 使用eventChannel向被打开页面传送数据(wx.navigateTo高级用法)

对于页面与页面之间的数据通信,一种方式是,可以通过url携带参数的方式跳转到指定的页面,在跳转的指定页面中的onLoad生命周期函数中的options中可以拿到数据

但是这种传递数据的方式是有限的,不适合数据多的情况下

另一种方式是可以传递数据没有限制,wx.navigateTo提供了一种更加高级的用法,通过eventChannel向被打开页面传送数据

# 父(当前)页面向子(目标)页面传递数据

当前页面-->目标页面是利用wx.navigateTo 中的 success 回调中使用 emit 触发,目标跳转页面用 on 监听

实现将当前页面的数据传递给目标页面中

那当前页面又如何获取目标页面的数据呢

# 父(当前)页面如何获取跳转(子/目标)页面中的数据

知道了当前页面向目标跳转页面传递数据,那么反过来,当前页面又如何接收跳转页面传递过来的数据?

# 结语

本文主要介绍 4 种在小程序当中页面与页面之间的传递数据常见方法,其中如何返回上一级页面,这些都是实际开发中经常会遇到的问题

每一种方法都有与之对应的应用场景,url 方式比较适合跳转,携带少量的数据,当多个页面需要共享同一个数据对象时,可以使用全局globalData对象,也可以使用本地缓存数据

以及最后一种使用 eventChannel 向被打开页面传送数据(wx.navigateTo高级用法)

它适合一种传递复杂的数据.

关于页面之间数据传递就介绍这么多,如果您有问题,欢迎补充,给我留言,一起学习成长

# 相关文档

关注公众号

一个走心,有温度的号,同千万同行一起交流学习

加作者微信

扫二维码 备注 【加群】

扫码易购

福利推荐