前言
最近遇到这么一个场景,需要在微信小程序里通过webview嵌入一个h5页面,h5页面需要传参给小程序,小程序收到参数后实时去做出某些行为,但是微信小程序是不支持webview和小程序双向通信的,只有规定的时机可以获取到收到额度参数,所以只能用比较取巧的方法
实现思路
webview跳转到小程序是通过路由跳转的,而且小程序里可以实时监听路由,那么就可以通过路由来传递参数
实现代码
html
//webview.html
<!DOCTYPE html>
<html lang="en">
<body>
<div class="content-part">
<button class="lkmeLogin">登录</button>
</div>
<script
type="text/javascript"
src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"
></script>
<script>
function jumpToMiniProgramPage(url) {
wx.miniProgram.getEnv(function (res) {
if (res.miniprogram) {
var data = {id:1};
var hashchangeFunc = (_) => {
var { callback: result } = JSON.parse(
location.hash.split("?")[1]
);
// 防止回调参数未取到
try {
result = decodeURIComponent(result);
result = JSON.parse(result || "{}");
} catch (e) {
result = {};
}
var { errNo, errMsg, res } = result;
if (errNo >= 0) {
resolve(result);
} else {
reject(result);
}
// 由于小程序改变了页面的hash,需要返回
history.back();
// 移除当前hashchange的监听
window.removeEventListener("hashchange", hashchangeFunc);
};
let joiner = url.indexOf("?") < 0 ? "?" : "&";
wx.miniProgram.navigateTo({
url: `${url}${joiner}${'data=' +JSON.stringify(data)}`,
});
window.addEventListener("hashchange", hashchangeFunc);
}
});
}
$(".lkmeLogin").on("click", function () {
var url = "/pages/pay/pay";
let msg = `\r\n\r\n当前location.href值为: ${location.href}\r\n并且马上返回上级页面防止url污染`;
jumpToMiniProgramPage(url)
.then(({ errNo, errMsg, res }) => {
alert(`获取成功: ${JSON.stringify(res)}` + msg);
})
.catch(({ errNo, errMsg, res }) => {
alert(`获取失败: ${errMsg}` + msg);
});
});
</script>
</body>
</html>
小程序代码
js
// pages/pay/pay.js
import {
setPageCallBack
} from "../../utils/util.js";
const { oneKeyLogin } = requirePlugin("auth-plugin");
Page({
/**
* 页面的初始数据
*/
data: {
params: "", // webview带给当前页面的参数
triggered: false, // 是否已触发回调的标记,在页面销毁时可判断是否执行回调
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
console.log(`webview传过来的入参:${JSON.stringify(options)}`);
let {
href,
...params
} = JSON.parse(options.data);
// url带过来的参数会被编码, 所以这里需要解码处理
this.setData({
href: decodeURIComponent(href),
params,
paramsToString: JSON.stringify(params)
});
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function() {
// 页面销毁, 还没执行过回调,默认失败
if (!this.data.triggered) {
setPageCallBack({
href: this.data.href,
});
}
},
});
js
//util/util.js
/**
* 描述: 设置 webview 页面操作完成给H5页面的回调事件, 并且返回webview页面
* @param: data {Object} 参数
* @param: callback {Object} 传给H5页面的参数
*/
export function setPageCallBack(
data = {
href: "",
},
callback = {
errNo: -1,
errMsg: "未执行回调直接返回",
res: {},
}
) {
console.info("回调事件的参数", data);
var pages = getCurrentPages();
console.log("我是获取的pages栈----------------------", pages);
var currPage = pages[pages.length - 1]; //当前页面
//上一个页面 (index page)
var prevPage = pages[pages.length - 2];
let {
href,
} = data;
let visitUrl = href+'#?'+ JSON.stringify({callback:callback});
console.log(`设置webview的url为:${visitUrl}`);
prevPage.setData({
visitUrl,
});
// 关闭当前webview
wx.navigateBack();
}
/**
* 配置webview来源地址
* @param {*} href webview的文件目录地址
* @param {*} callback 回调给webview的callback字符串
*/
export function getWebviewHref(href, callback) {
// 取url的query参数
// 单独处理hash的query参数
let query = href.split("?")[1] ? JSON.parse(href.split("?")[1]) : {};
if (typeof callback === "object") callback = JSON.stringify(callback);
Object.assign(query, {
callback,
});
// 防止当前webview的url不存在hash出错
var hash = "#";
console.log(`callback:${callback}`);
console.log(`query:${JSON.stringify(query)}`);
if (JSON.stringify(query) !== "{}") {
hash += "?" + JSON.stringify(query);
}
return href + hash;
}