在开发小程序的时候,会碰到页面间进行跳转的需求,小程序间页面跳转的方法有很多,大体分为两类,一个是指令方式,一个是用过js控制。

一、js控制跳转

1、wx.navigateTo

wx.navigateTo用于保留当前页面、跳转到应用内的某个页面,使用 wx.navigateBack可以返回到原页面。对于页面不是特别多的小程序,通常推荐使用 wx.navigateTo进行跳转, 以便返回原页面,以提高加载速度。当页面特别多时,则不推荐使用。

// 保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。
// 注意:调用 navigateTo 跳转时,调用该方法的页面会被加入堆栈,但是 redirectTo 
wx.navigateTo({
  url: 'page/home/home?user_id=111'
})

2、wx.navigateBack

wx.navigateBack用于关闭当前页面,并返回上一页面或多级页面。开发者可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。这个 API 需要填写的参数只有 delta,表示要返回的页面数。若 delta 的取值大于现有可返回页面数时,则返回到用户进入小程序的第一个页面。当不填写 delta 的值时,就默认其为 1(注意,默认并非取 0),即返回上一页面

// 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。

wx.navigateTo({
  url: 'page/home/home?user_id=111'  // 页面 A
})
wx.navigateTo({
  url: 'page/detail/detail?product_id=222'  // 页面 B
})
// 跳转到页面 A
wx.navigateBack({
  delta: 2
})

3、wx.redirectTo

wx.redirectTo当页面过多时,被保留页面会挤占微信分配给小程序的内存,或是达到微信所限制的 5 层页面栈。这时,我们应该考虑选择 wx.redirectTo。wx.redirectTo()用于关闭当前页面,跳转到应用内的某个页面。这样的跳转,可以避免跳转前页面占据运行内存,但返回时页面需要重新加载,增加了返回页面的显示时间。

// 关闭当前页面,跳转到应用内的某个页面。
wx.redirectTo({
  url: 'page/home/home?user_id=111'
})

4、wx.switchTab

tabBar页面专用,对于跳转到 tab bar 的页面,最好选择 wx.switchTab(),它会先关闭所有非 tab bar 的页面。其次,也可以选择 wx.reLaunch(),它也能实现从非 tab bar 跳转到 tab bar,或在 tab bar 间跳转,效果等同 wx.switchTab()。使用其他跳转 API 来跳转到 tab bar,则会跳转失败。

// 跳转到tabBar页面(在app.json中注册过的tabBar页面),同时关闭其他非tabBar页面。
wx.switchTab({
  url: 'page/index/index'
})

5、wx.reLaunch

wx.reLaunch()与 wx.redirectTo()的用途基本相同, 只是 wx.reLaunch()先关闭了内存中所有保留的页面,再跳转到目标页面。

// 关闭所有页面,打开到应用内的某个页面。
wx.reLanch({
  url: 'page/home/home?user_id=111'
})

二、指令式跳转

// navigator 组件默认的 open-type 为 navigate 
<navigator url="/page/navigate/navigate?title=navigate" hover-class="navigator-hover">跳转到新页面</navigator>
// redirect 对应 API 中的 wx.redirect 方法
<navigator url="../../redirect/redirect/redirect?title=redirect" open-type="redirect" hover-class="other-navigator-hover">在当前页打开</navigator>
// switchTab 对应 API 中的 wx.switchTab 方法
<navigator url="/page/index/index" open-type="switchTab" hover-class="other-navigator-hover">切换 Tab</navigator>
// reLanch 对应 API 中的 wx.reLanch 方法
<navigator url="../../redirect/redirect/redirect?title=redirect" open-type="redirect" hover-class="other-navigator-hover">关闭所有页面,打开到应用内的某个页面</navigator>
// navigateBack 对应 API 中的 wx.navigateBack 方法
<navigator url="/page/index/index" open-type="navigateBack" hover-class="other-navigator-hover">关闭当前页面,返回上一级页面或多级页面</navigator>

navigator的open-type属性 可选值 'navigate'、'redirect'、'switchTab',对应于wx.navigateTo、wx.redirectTo、wx.switchTab的功能:

open-type="navigate"等价于API的 wx.navigateTo 

而wx.navigateTo的url是需要跳转的应用内非 tabBar 的页面的路径

open-type="redirect"等价于API的 wx.redirectTo 而wx.redirectTo的url是需要跳转的应用内非 tabBar 的页面的路径 open-type="switchTab"等价于API的 

wx.switchTab而wx.switchTab的url是需要跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。

三、页面通信

1、使用url 路径传递

1.1、传递普通字符串

通过在url后面拼接参数,参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 ‘path?key=value&key2=value2’。

// A页面跳转代码
goB(){
    wx.navigateTo({
      url: '/pages/B/index?id=value',
    })
  },

// B页面接收代码
onLoad: function (options) {
    console.log('id', options.id)
}

1.2、传递对象

上面的案例是字符串参数,但是很多情况下需要传递对象。这个时候需要先把对象通过JSON.stringify(obj)将 object 对象转换为 JSON 字符串进行参数传递,再到接收页面通过JSON.parse解析使用。

// A页面跳转代码
goB(){
   let userStr = JSON.stringify(this.data.userInfo)
   wx.navigateTo({
     url: '/pages/B/index?id='+userStr,
   })
 }

// B页面接收代码
onLoad: function (options) {
    console.log('id', JSON.parse(options.id))
  }

2、使用globalData 全局变量

globalData是小程序app.js中固定的一个属性,存储的数据可在全项目任意处使用

// app.js
App({
  globalData:{},
})

// aaa.js
const app = getApp();
app.globalData.name='xiaowang';

// bbb.js
const app = getApp();
console.log(app.globalData.name) //xiaowang

3、使用storage 数据缓存

storage是微信分给每个小程序的缓存,单个参数最大1M,数据总和最大10M

// aaa.js
Page({
    data:{
        name:'xiaowang'    
    },
})
//只支持原生类型、Date、及能够通过JSON.stringify序列化的对象
wx.setStorageSync('name',this.data.name)

// bbb.js
console.log(wx.getStorageSync(name)) //xiaowang

4、事件通信

通过事件通信通道

// A页面跳转代码
goB() {
    wx.navigateTo({
      url: '/pages/B/index',
      success:(res)=>{
            // 发送一个事件
            res.eventChannel.emit('toB',{ userInfo: this.data.userInfo })
        }
    })
  }

// B页面接收代码
onLoad: function (options) {
     // 获取所有打开的EventChannel事件
     const eventChannel = this.getOpenerEventChannel();
     // 监听 index页面定义的 toB 事件
     eventChannel.on('toB', (res) => {
       console.log(res.userInfo) 
     })
   }

在A-B-C多个页面直接建立数据通道

//注意this.getOpenerEventChannel() 只能在navigateTo模板页面使用,其他更多页面使用时,
//可以保存在getApp()全局实例中以备其他页面使用
// 保留AB通道事件,已备C页面给A页面发送数据
// B页面
    const eventChannel = this.getOpenerEventChannel()
    getApp().pageBEventChannel = eventChannel
//C页面 
 getApp().pageBEventChannel.emit('PageAacceptDataFromPageC', { data: 'Page C->A' });

5、使用第三方iny bus 事件

5.1、安装

方式一. 通过 npm 安装

# npm
npm i iny-bus -save

# yarn
yarn add iny-bus --production

方式二. 下载代码

直接通过 git 下载 iny-bus 源代码,并将dist目录 中的 index.js 拷贝到自己的项目中

git clone https://github.com/landluck/iny-bus.git

5.2、使用

使用内置方法

// App、Page、Component 使用方法一致
  import bus from 'iny-bus'

  // bus.app bus.page bus.component
  const page = bus.page({
    busEvents: {
      // 简单使用
      postMessage(msg) {
        this.setData({
          msg
        })
      },
      // 一次性事件
      postMessageOnce: {
        handler (msg) {
          this.setData({
            msg
          })
        },
        once: true
      }
    },
    onLoad() {
      bus.emit('postMessage', 'hello bus')
      bus.emit('postMessageOnce', 'hello bus once')
    }
  })

  Page(page)

在生命周期中使用

// 小程序
  import bus from 'iny-bus'

  // 添加事件监听
  // 在 onLoad 中注册, 避免在 onShow 中使用
  onLoad () {
    this.eventId = bus.on('事件名', (a, b, c, d) => {
      // 支持多参数
      console.log(a, b, c, d)

      this.setData({
        a,
        b,
        c
      }
    })
  }

  // 移除事件监听,该函数有两个参数,第二个事件id不传,会移除整个事件监听,传入ID,会移除该页面的事件监听,避免多余资源浪费, 在添加事件监听后,页面卸载(onUnload)时建议移除
  onUnload () {
    bus.remove('事件名', this.eventId)
  }
 
  // 派发事件,触发事件监听处更新视图
  // 支持多参传递
  onClick () {
    bus.emit('事件名', a, b, c)
  }
  
  // 清空所有事件监听
  onClear () {
    bus.clear()
  }