原始问题
前段时间用taro做了一个移动端网页,这两天要改为小程序,发现h5特有的api用太多了,小程序版本跑不起来了,想了下就用小程序放一个webview组件放这个网页吧。
但是发现了一个严重的问题,小程序直接打开这个webview进入内页无返回按钮!
就是顶部这个控制返回的胶囊按钮
内页返回探索
在设置了小程序的配置 navigationStyle: ‘default’ 通过NavgatorTo进入第二个小程序页面就有返回按钮的了,
那我们就可以打开小程序的时候是一个空白页,onLoad时候直接NavgatorTo跳转到我们的webview页面,这样webview就带返回按钮了。
这样做有一个尴尬的问题,
进入小程序就有一个切换效果,而且进入内页返回到最后一页就又到了这个空白页。
最终解决方案
要点
- 两个webview,一个做首页,一个做内页;
- 通过微信sdk window.wx.miniProgram.navigateTo api 在h5跳转到小程序的页面。
坑
- window.wx.miniProgram.navigateTo({url:
../h5/webview?weburl=http://192.168.31.98:10086/#/${path}
}); url传递url path如果里包含?和&后边会被截断。
可以用这个encodeURIComponent加密传输
wvNavTo = (path) => {
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
// url传递url不能带?,否则Taro.getCurrentInstance().router.params获取不到?后边的参数
let url = fixedEncodeURIComponent(`http://172.19.133.243:10086/#${path}`)
window.wx.miniProgram.navigateTo({ url: `/pages/index/index?weburl=${url}` });
}
}
- 微信sdk需要1.3.2以上的 可以用这个。
- 在第二个webview里准备着接收url的方法,当通过sdk跳转过来后直接跳转到相应的url里,第一个webview同理
componentDidMount() {
try {
// @ts-ignore
let { weburl } = Taro.getCurrentInstance().router.params as string;
weburl = decodeURIComponent(weburl);
this.setState({
weburl, //获取H5页面传递过来的weburl
});
} catch (error) {
console.log("weburl set error",error);
}
}
原理解释
1、在小程序里的H5可以通过sdk跳转到小程序页面window.wx.miniProgram.navigateTo。
2、小程序设置navigationStyle: ‘default’ 通过NavgatorTo进入第二个小程序页面就有返回按钮的了,而且这个按钮对于webview容器里嵌套的网页返回也起作用,会执行webview goback操作,如果webview容器的页面栈为0层则退回上一个小程序页面,这些完全不需要自己判断。
3、我们把四个首页放到第一个webview里,所有的内页跳转都通过window.wx.miniProgram.navigateTo跳转到第二个webview里并进入对应的页面,这样webview内页就有返回按钮了,所有的内页进入首页都跳转到第一个webview里,这样首页也都没有返回按钮了。
小程序分享问题
- 分享后使用postmessage发送一个请求,值为webview要分享的url;
- webview容器接收这个值,放在state里做响应处理;
- 注意postmessage并不是实时触发的,而是在特定的时机才会触发,小程序销毁,后退等,所以onMessage会收到多条数据,每次取最后一条就好了。
// h5分享时调用这个方法,把要分享的url传递进去,包括拼接的特定的参数等。 /** * 传递分享的url */ setMinShareInfo: function (url) { var obj = { webshareurl: url, }; window.wx.miniProgram.postMessage({ data: obj }); },
// pages/index/index.tsx
import React, { Component } from 'react';
import { WebView, View } from '@tarojs/components';
import Taro from '@tarojs/taro';
import './index.scss';
/**
* 作为webview内页
*/
export default class Index extends Component {
state = {
pathroute:'',
weburl: '',
shareUrl: `/pages/index/index?weburl=https://****.***.com/app/index.html#/pages/index/index?flagMini=InMini`,
};
componentDidMount() {
try {
// @ts-ignore
let { weburl } = Taro.getCurrentInstance().router.params as string;
weburl = decodeURIComponent(weburl);
this.setState({
weburl, //获取H5页面传递过来的weburl
});
} catch (error) {
console.log('weburl set error', error);
}
}
/**
* 小程序右上角分享触发的事件
*
* @param res
* @returns
*/
onShareAppMessage(res) {
return {
title: '分享标题',
path: this.state.shareUrl,
};
}
handleMessage = val => {
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
try {
const data = val?.detail?.data
// 取postmessage的最后一个
this.setState({
shareUrl: `/pages/index/index?weburl=${fixedEncodeURIComponent(
data?.[data.length - 1]?.webshareurl,
)}`,
pathroute: data?.[data.length - 1]?.webshareurl.slice(40),
});
} catch (error) {
console.log('handleMessage error: ', error);
}
};
render() {
return <WebView onMessage={this.handleMessage} src={this.state.weburl} />;
}
}