小程序如何实现跨页面通信

前言

最近有很多同学问我,小程序里面如何进行跨页面通信。看了下之前的老代码,基本都是基于onShow或者localStorage。虽然可以实现,但是并不怎么优雅。

今天就来聊一聊,小程序的跨页面通信的几种实现方案。或许会有你想要的方案(优雅…)

方式一:onShow + localStorage

业务场景:页面一未登录跳转至登录页面,登录成功后返回页面一,页面一需要更新当前登录态




{{ name }}
当前是否登录:{{ isLogin ? '是' : '否' }}





import { ref } from 'vue'
import taro, { useDidShow } from '@tarojs/taro'
const name = ref('前端南玖---小程序页面通信')
const loginStatus = taro.getStorageSync('isLogin') || false
const isLogin = ref(loginStatus)

const gotoLogin = () => {
taro.navigateTo({
url: '/pages/login/index'
})
}
// 小程序onshow生命周期,从localStorage获取是否登录,更新页面
useDidShow(() => {
const loginStatus = taro.getStorageSync('isLogin') || false
isLogin.value = loginStatus
})




登录页面





import taro from '@tarojs/taro'
const login = () => {
taro.login({
success: function (res) {
console.log('登录成功', res)
taro.setStorageSync('isLogin', true)
taro.navigateBack()
},
fail: function (res) {
console.log('登录失败', res)
}
})
}

优点:这种方案可能是最简单的通信方案,比较容易理解

缺点:如果完成通信后,没有即时清除通信数据,可能会出现问题。另外因为依赖localStorage,而localStorage可能出现读写失败,从面造成通信失败

方式二:onShow + globalData

业务场景同上

这个方案与第一个方案差不多,只不过是将localStorage换成了globalData

Taro框架想要使用小程序的globalData需要使用Taro提供的插件 setGlobalDataPlugin

// app.ts
import { setGlobalDataPlugin } from '@tarojs/taro'

const App = createApp({
})

// 注册全局数据
App.use(setGlobalDataPlugin, {
  isLoginfalse// 是否登录
})
// 页面一
// ...

import { ref } from 'vue'
import taro, { useDidShow } from '@tarojs/taro'
const app = taro.getApp()
const name = ref('前端南玖---小程序页面通信')
const loginStatus = taro.getStorageSync('isLogin') || false
const isLogin = ref(loginStatus)

const gotoLogin = () => {
  taro.navigateTo({
    url'/pages/login/index'
  })
}

// 使用globalData
useDidShow(() => {
  // const loginStatus = taro.getStorageSync('isLogin') || false
  console.log('app.globalData', app.isLogin)
  const loginStatus = app.isLogin || false
  isLogin.value = loginStatus
})
// 登录页
import taro from '@tarojs/taro'
const app = taro.getApp()
const login = () => {
  taro.login({
    successfunction (res{
      console.log('登录成功', res)
      app.isLogin = true
      taro.navigateBack()
    },
    failfunction (res{
      console.log('登录失败', res)
    }
  })
}

优点:实现简单,容易理解。因为不用读写localStorage,直接操作内存,所以相比方式1,速度更快,更可靠

缺点:同方式1一样,要注意globalData污染

方式三:eventBus发布订阅

我们还可以通过实现一个中央事件总线,通过发布订阅实现跨页面通信。

// eventBus
export default class EventBus {
  private static instance: EventBus
  private listeners: RecordFunction[]>

  private constructor() {
    this.listeners = {}
  }

  public static getInstance() {
    if (!EventBus.instance) {
      EventBus.instance = new EventBus()
    }
    return EventBus.instance
  }

  public on(event: string, callbackFunction) {
    if (!this.listeners[event]) {
      this.listeners[event] = []
    }
    this.listeners[event].push(callback)
  }

  public off(event: string, callbackFunction) {
    if (!this.listeners[event]) {
      return
    }
    const index = this.listeners[event].findIndex((listener) => listener === callback)
    if (index !== -1) {
      this.listeners[event].splice(index, 1)
    }
  }

  public emit(event: string, ...args: any[]) {
    if (!this.listeners[event]) {
      return
    }
    this.listeners[event].forEach((listener) => listener(...args))
  }
}
// app.ts
import EventBus from './utils/eventBus'
// 注册全局事件总线
App.config.globalProperties.$bus = EventBus.getInstance()
// 页面一
import { onMounted, ref, getCurrentInstance } from 'vue'
import taro, { useDidShow } from '@tarojs/taro'
const $bus = getCurrentInstance()?.appContext.config.globalProperties.$bus

onMounted(() => {
  // 订阅登录状态
  isLogin.value = $bus.on('loginStatus', (status: boolean) => {
    console.log('$bus', status)
    isLogin.value = status
  })
})
// 登录页
import taro from '@tarojs/taro'
import { getCurrentInstance } from 'vue'
const $bus = getCurrentInstance()?.appContext.config.globalProperties.$bus
const login = () => {
  taro.login({
    successfunction (res{
      console.log('登录成功', res)
      // 发布登录状态
      $bus.emit('loginStatus'true)
      taro.navigateBack()
    },
    failfunction (res{
      console.log('登录失败', res)
    }
  })
}

这种方式看着是比前两种优雅了不少,但缺点是需要维护发布的事件,避免重复绑定。

方式四:小程序的EventChannel

页面间事件通信通道

  • EventChannel.emit(string eventName, any args) :触发一个事件

  • EventChannel.on(string eventName, function fn) :持续监听一个事件

  • EventChannel.once(string eventName, function fn) :监听一个事件一次,触发后失效

  • EventChannel.off(string eventName, function fn) :取消监听一个事件。给出第二个参数时,只取消给出的监听函数,否则取消所有监听函数

EventChannel借助wx.navigateTo方法,在两个页面之间构建起了数据通道,互相可以通过“派发事件”及“注册这些事件的监听器”来实现基于事件的页面通信。

// 页面一

const gotoLogin = () => {
  taro.navigateTo({
    url'/pages/login/index',
    events: {
    // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
    acceptDataFromLoginPagefunction(data{
      console.log('来自登录页的数据', data)
      isLogin.value = data.loginStatus
      },
    },
    successfunction(res{
      // 通过eventChannel向被打开页面传送数据
      res.eventChannel.emit('acceptDataFromIndexPage', { data'nanjiu from index' })
    }
  })
}
// 登录页
import taro, { getCurrentPages } from '@tarojs/taro'
const current = getCurrentPages().pop()
const eventChannel = current?.getOpenerEventChannel()
eventChannel.on('acceptDataFromIndexPage'function(data{
  console.log('来自首页的数据', data)
})
const login = () => {
  taro.login({
    successfunction (res{
      console.log('登录成功', res)
      eventChannel.emit('acceptDataFromLoginPage', { data: res.code, loginStatustrue })
      taro.navigateBack()
    },
    failfunction (res{
      console.log('登录失败', res)
    }
  })
}

© 版权声明
THE END
喜欢就支持一下吧, 不喜欢也支持一下吧
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称常用语 夸夸
夸夸
还有吗!没看够!
表情代码图片

    暂无评论内容