小程序怎么与h5双向通信?进来讨论讨论吧

2,303 阅读3分钟

我正在参加「掘金·启航计划」

前言

最近在处理小程序相关的业务,是小程序+h5的混合开发,应该也是大部分小程序的开发模式。很多时候,我们需要借助小程序调起一些原生功能,来实现更好的用户交互。这时候就需要h5传递参数给小程序,小程序调用接口获取信息后,再回传h5。

Page 1 (1).png

正文

从上图不难看出,其中最为重要的就是双方的通信实现。

小程序 --> h5

<web-view src="http://127.0.0.1?foo=bar"></web-view>

在不借助服务器的情况下,小程序想传递信息给h5,只有通过拼接url的方式,一般用于传递登录token。

h5 --> 小程序

1、postMessage

官方文档可以得知,h5可以通过JSSDK提供的wx.miniProgram.postMessage向小程序发送信息,同时<web-view>组件需要绑定bindmessage事件。

<!--miniprogram-->
<web-view src="http://127.0.0.1" bindmessage="handleMessage"></web-view>
// h5
wx.miniProgram.postMessage({ data: {foo: 'bar'} })

1677248066(1).jpg

但是请注意,文档中说明了bindmessage事件只会在小程序后退、组件销毁、分享三个时机触发。 我不知道这个特定时机是因为技术限制还是因为出于什么角度的考虑,但是这对于我们开发人员是极其不友好的,如果有老哥知道其中原因,麻烦在评论区告知一声。

因为上述三个时机根本不符合开发的正常通信,所以根本无法使用。

2、navigateTo、redirectTo

wx.miniProgram.navigateTo({ url: '/pages/test/index?foo=bar' })

然后小程序会在onLoad生命周期通过options获取到传递的参数。

这种方式的缺点就是打开了新页面,你可能会使用redirectTo,而redirectTo的问题在于用户取消了操作,想返回上一页的时候,是前前页面。还有一个问题在于,小程序获取到所需数据,需要将其再次传回h5,所以需要再打开一个webview传递信息,这时候可以使用redirectTo,如果是将数据传递给另外的h5页面,则不会有后面的问题,但如果是需要将数据传递回原来的h5页面,那么页面栈这时候存在了两个相同的h5页面。

而调用拍照功能的时候,用户很有可能对拍摄的照片不满意,这时候要重新进行一轮调用小程序原生相机功能,就会产生重复的路由栈问题。

Page 1 (2).png

OK,铺垫了那么久,终于要讲到本文的重点了。以下是小弟关于解决重复路由栈的一个思路,用来抛砖引玉,如果各位老哥有更好的解决方案,可在评论区一同探讨。

解决重复路由栈

  1. h5传递参数给小程序:
wx.miniProgram.navigateTo({ url: '/pages/test/index?storageKey=foo' })
  1. 小程序获取到数据后,打开webview,跳转到一个miniPage中间页
wx.redirectTo({
    url: `/pages/webview/index?url=encodeURIComponent(${http://127.0.0.1/miniPage?storageKey=foo&storageValue=bar})`
})
<web-view src="http://127.0.0.1/miniPage?storageKey=foo&storageValue=bar"></web-view>

storageKey是h5传递过来指定的值,storageValue是获取到的数据。

  1. miniPage从url获取storageKeystorageValue
localStorage[storageKey] = storageValue;
wx.miniProgram.navigateBack();

将获取到的key和value存到localStorage中。同时,调用wx.miniProgram.navigateBack返回原来的h5页面。

  1. h5页监听storageEvent事件
window.addEventListener('storage', function(e) {
    if(e.key == storageKey && e.newValue) {
        /**
         * do something
         */
        localStorage.removeItem(storageKey);
    }
});

需要对key进行判断,是否与最初传给小程序的storageKey一致。

这样就获取到小程序传递过来的数据,并且不会有重复路由栈问题。

Page 1 (3).png

结语

上面方案的主要思想就是利用storageEvent事件,结合一个中间页,实现路由栈的抵消。歪楼打个广告,关于操作storage, 之前实现了一个快捷管理storage的包——proxy-web-storage,详细介绍可以看我之前的文章——【开源项目】看了vue的源码,我用proxy实现了更强大的storage。欢迎大家尝试使用看看,给点建议。

今天的分享就到这里了,如果各位老哥对文章有任何看法,可以在评论区提出,欢迎大家进行讨论。