详解小程序中h5页面onShow实现及跨页面通信方案

小程序webview的现状

h5页面在小程序中的交互(跳转)场景

h5跳转小程序native页面(如:调用小程序地址选择能力,然后返回对应的地址信息给h5页面)

h5跳转己方业务线的h5页面(内部页面交互,方式比较多样)

h5跳转其它业务线的h5页面(如:交易流程,相关页面可能有其他业务线提供)

主要痛点

在完成相关操作后, 页面状态需要更新 ,目前常见的更新方式有如下两种:

第一种:通过url传参(如:url中加入__isonshowrefresh=1,告诉webview再次onshow时候刷新),把需要传递的参数拼接到url中,重新打开url。

第二种:需要跳转到新的页面进行数据更新(如:下单页 - 地址选择页 - 新的下单页)

第一种方案,功能上没有问题,但会导致页面刷新,如果页面操作复杂,需要多次刷新

第二种方案,正向操作时体验比方案一好,但导致了另外一个问题:操作 跳转层级过深 ,尤其返回的时候简直让人崩溃。

小程序中,h5页面打开新页面方式

我们先来看下小程序中常见的h5跳h5的方式:

方式1:直接用location.href跳转,返回时候各机型表现不一致,有的会刷页面,重新执行js,有的会直接展示之前的缓存

方式2:通过路由hash跳转,返回触发hashchange,页面不刷新,js层面重现渲染

方式3:跳转页面打开一个新的webview,相当于每个页面都是一个独立的webview

我们采用的是方式3,理由如下:

打开新页面时的效果更趋近于native间的跳转(当然新打开的页面也会重新加载静态资源,同时这也有另一个问题,一旦你打开10个层级后,再打开新的webview就没反应了,这个是小程序10层限制)

返回的体验也更趋近于native,同时保证页面状态统一(不会出现有的直接展示,有的会重新执行js)

webview通过this.src拿到的链接即为当前页面链接,因为如果页面自行通过路由和location.href跳转,页面链接变更后,webview并不会知晓,这种方案,webview通过this.src拿到的链接始终是当前页面的链接。

由于这种方案可能会达到小程序的10层限制。所以在一些重要页面建议加入“ 回到首页 ”的操作,通过这个操作来缩短小程序历史栈

回到首页方案简述

(如果不感兴趣这部分可以直接略过)

wx.miniProgram.reLaunch({ url: '/pages/webview/bridge?url=项目首页地址' })

先声明,我们webview的路径是/pages/webview/webview

/pages/webview/bridge是个中转页,有如下特点: 该页面并 不是最终打开h5页面的webview页 ,而是一个 中转页

主要用作返回处理

页面逻辑: 如果是第一次展示,则跳转/pages/webview/webview,同时把url传过去,正常打开h5

如果不是第一次展示,说明是从webview返回过来的,直接重定向到小程序首页

这个中转页:主要保证reLaunch到某h5页面后,用户仍然可以点击返回到小程序首页。

该方案通常用于:小程序中内嵌了多个业务线的h5页面这种场景。

一个内容发布场景

我们从首页进入发布页,完成发布后,跳转至商品详情页

那么对于一个新用户来讲,整个操作过程是这样的:

首页(点击发布)

进入发布页面(选择发布商品的分类)

进入商品分类页(选择完成后)

将分类id拼入url,进入新的发布页面(选取件地址)

进入地址列表页(如果新用户是没有地址的,点击新增地址)

进入新增地址页(添加完成后)

将地址id拼如url,进入又一个新的发布页面(编辑完信息后点击发布)

进入发布成功页(点击查看商品详情)

进入商品详情页

这个场景就是同一个页面,里面不同的内容项需要跳转不同的页面去操作,然后再回到原来页面更新状态的问题。

假如商品详情页没有“回到首页”的入口,那么这个用户要想回到首页。。。需要按8次“返回” = =!

经过这个体验后,我想一般的用户是没有勇气再发布内容的。

当然也有另一种这种折中方案

就是商品提到的,在连接中加入某个标志位,比如在url中加入__isonshowrefresh=1,webview在打开连接时候,会去读取这个参数,如果有,则每次在onShow时候,重新加载url,通过刷新页面进行页面状态更新。

这个体验也不爽,就是在复杂的页面会多次刷新。

声明

我下面要讲的这个方案并不是停留在设想阶段,它已经在线上跑了

想看效果的朋友,可以在微信小程序中搜:

“转转二手交易网”-“0元免费领”-(底部)“送闲置赚星星”-进入到发布页后

分类(跳转h5,选中内容后返回,将参数传给之前的h5)

取件地址(跳转native原生地址选择,选中后返回,将参数传给之前的h5)

OK,我们进入今天的主题

小程序中h5页面onShow和跨页面通信的实现

首先想到的就是onShow方法的实现,之前有人提议用visibilitychange来实现onShow方法。

但调研过后,这种方式在ios中表现符合预期,但是在安卓手机里,是不能按预期触发的。所以该方案被我否了。

于是就有了下面的方案

原理介绍

这个方案需要h5和小程序的webview都做处理。

核心思想: 利用webview的hash特性

详解小程序中h5页面onShow实现及跨页面通信方案

 

小程序通过hash传参,页面不会更新(这个和浏览器一样)

h5可以通过hashchange捕获最新参数,进行自定义逻辑处理

最后执行window.history.go(-1)

为什么要执行window.history.go(-1)

这一步是整个方案的精髓:

因为hash变更会导致webview历史栈长度+1,用户需要多一次返回操作。但这一步明显是多余的。

同时window.history.go(-1)后,会把webview在hash中添加的参数去掉,还能保证和之前的url一致。

 方案延伸(跨页面数据传递)

小程序里另个一常见的场景就是调用第三业务(或者己方业务),在做完某些操作后需要把选中的数据带回之前的页面。

如前面提到的例子:发布页,需要选择发布类型,然后返回,发布页发布类型局部更新

当然有些同学会说:我可以用setInterval,监控localStorage。在新页面选中内容后,设置localStorage,然后在返回不就可以了。

我这里说的是 通用方案 。如果页面都是由己方业务线维护的当然可以随便折腾。

但是一旦涉及到第三方业务线,尤其不同域名页面的业务调用,这种通信方式就尴尬了。

那我的方案怎么处理呢,我总结了一张图

详解小程序中h5页面onShow实现及跨页面通信方案

我们来解读一下这张图:

webview1打开发布页面,h5绑定hashchange事件(因为webview通过hash传值时会触发该事件)

将自定义的onShow方法缓存。在hashchange触发时,寻找指定参数,如果存在则触发

用户点击跳转到类型选择页

这时会打开一个新的webview2页面实例,打开类型选择页

用户操作完成,调用wx.miniProgram.postMessage把数据发送给webview,并返回

webview由于绑定了bindmessage事件,在返回时会接收到h5发送的数据

同时将接收到的数据缓存在一个全局的store中,webview2销毁,小程序执行返回

从webview2返回到webview1,这时webview1的onShow钩子会触发

webview1读取全局的store,将要发送的参数取出,拼接h5链接的hash部分,并重新打开该链接

虽然重新打开链接,由于仅仅是hash部分的变化,所以页面不会刷新

但会触发h5页面的hashchange,此时调用用户自定义的onShow方法,读取hash参数,进行页面更新

h5页面在执行完onShow方法后,调用window.history.go(-1),恢复历史栈

整个过程就是这样

代码示意:

小程序

小程序webview要先做几方面考虑:

出于平滑接入的考虑,不能上来搞一刀切,要保证现有页面再不做任何修改的情况下继续访问。

新能力要通过额外参数区分,如:检测url中的query部分,带有__isonshowpro=1再进行通过hash方式传参。

改造原有逻辑,让__isonshowpro=1时,hash处理逻辑优先级最高

参数定义,在前面加入了两个下划线,目的是为了分区url中正常的参数

小程序端webview.wpy

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/6644dc59318e6781fa936b8f11b244ed.html