利用H5的hash特性来做数据交换
前言
目前小程序页面回退H5是无法带入数据的,例如用户A在H5上选择拍照,跳转到小程序页面拍照压缩并将照片地址带回H5展示出来。小程序与H5之间的交互目前只有官方给出的postMessage接口,并且只能在满足特定时机下触发message事件才能拿到数据。为满足日益繁杂的产品需求,提高迭代速度,又不能放弃小程序的优势功能,因此需要打通小程序与H5的数据交换。
实现方案
利用H5的hash特性,使H5知道有数据变化,并且页面不会刷新,如下图所示流程:
关于windows.history.go(-1)
hash变更会导致页面历史栈长度+1,执行window.history.go(-1)保证和之前的url一致,并且history.go(-1)只后退不刷新,而history.back()后退+刷新。
踩坑
① webview的src是固定的,不会随着H5地址的变化而改变,因此H5跳转小程序需要将当前页面的url传递过去,设置H5的数据时回传过去,然后在onShow中重新组合url;
② 改变的hash值必须要和之前的不同,确保webview的src更新,触发H5的hashchange。
使用示例
小程序跳转H5
1wx.navigateTo({
2url: 'webview路径' + `?src=${
encodeURIComponent(h5地址)}`3})
H5跳转小程序
1window.wx.miniProgram.navigateTo({
2//backUrl参数跳转的小程序页面会记住,以供后续回传使用3url: '小程序页面地址...' + `&backUrl=${
encodeURIComponent(H5当前页面的地址location.href)}`4})
小程序代码示例
1Page({
2data: {
3src: '',
4canHtml: wx.canIUse && wx.canIUse('web-view')
5},
6onLoad(options) {
7let src = decodeURIComponent(options.src || '').replace(/(^\s*)|(\s*$)/g, '');
8//记录h5初始的URL
9this.baseUrl = src;
10this.setData({
11src: src || ''
12})
13},
14/**15* 设置H5的数据16* @param {Object} res - { data: 'xxx', backUrl: 'xxx' }17*/
18setH5Data(res) {
19//这里处理上面提到踩坑的第二点,v: Date.now()时间戳确保拼接webview的src与上一次的不同,触发H5的hashchange
20this.miniappData = encodeURIComponent(JSON.stringify({
data: res.data, v: Date.now()}));
21this.backUrl = res.backUrl ? decodeURIComponent(res.backUrl) : this.baseUrl;
22},
23onShow() {
24//h5站使用的是vue路由hash模式,这里直接拼接数据
25if (this.miniappData) {
26let src = this.backUrl + (this.backUrl.indexOf('?') > -1 ? '&' : '?') + `_miniappData=${
this.miniappData}`;
27this.miniappData = null;
28this.setData({
29src
30})
31}
32}
33})
小程序
传值给H5
注意:
小程序返回H5先调用setH5Data方法传递数据再返回,参数格式 { data: ‘xxx’, backUrl: ‘xxx’
1goH5Page(data) {
2let pages = getCurrentPages();
3let pre = pages[pages.length - 2];
4pre.setH5Data && pre.setH5Data({
5data: data,
6backUrl: this.backUrl
7});
8wx.navigateBack();
9}
监听示例:vue路由hash模式
1watch: {
2"$route.query._miniappData": {
3handler(val) {
4//vue有子路由,this.routePath记录了当前页的地址,如果当前是子路由,则只触发子路由的监听
5if (val && this.$route.path == this.routePath) {
6window.history.go(-1); //这个是核心
7let res = JSON.parse(decodeURIComponent(val)).data || "";
8xxx 业务逻辑
9}
10},
11deep: true
12}
13}
Tips
-
上述示例是基础实现,有其他业务需求可扩展
-
该功能已上线,体验很棒
交互展示
在下面的录屏展示中,除了《拍照识别身份证》页面为小程序的,其余的所有页面都是h5页面。