微信小程序 WebView 与 Vue H5 实时通讯实战指南
最近实现一个功能需要在小程序嵌入其它系统内部的一个页面(用vue写的H5页面),但小程序是无法使用iframe的,所以最终选择小程序官方的webview实现。
参考文档
微信小程序里用 WebView 嵌入 Vue H5 页面,要实现双向实时通讯,确实容易踩坑,但完全可行!下面给你一个实战总结,帮你少走弯路。
背景
- 小程序通过
<web-view>
组件嵌入外部 H5 页面(Vue 构建)。 - 需要实现:
- H5 主动给小程序发送消息
- 小程序给 H5 发送消息并接收响应
在 app.json
中配置 WebView
的合法域名。
{
"pages": [
"pages/index/index",
"pages/webview/webview"
],
"webview": {
"url": "https://example.com"
},
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序的地理位置功能"
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
核心思路
- 小程序 ↔ WebView 通讯依赖
postMessage
机制 - 小程序端监听
<web-view>
的bindmessage
事件。 - H5 页面通过
window.wx.miniProgram.postMessage()
给小程序发送消息。 - 小程序通过
webViewContext.postMessage()
给 H5 页面发消息。
网页向小程序
postMessage
时,会在特定时机(小程序后退、组件销毁、分享)触发并收到消息。e.detail = { data }
,data
是多次postMessage
的参数组成的数组
注意:postMessage的data键名不能改,不然取不到数据。
微信小程序的webview中postMessage,会把信息(对象)提交到一个消息队列,而这个消息队列只会在特定的场景(组件销毁或分享)才会触发。不适合实时的数据传递,比较适合数据上报这种场景。使用时对这个消息队列(数组)遍历,最好对每一次postMessage的对象格式进行约定,以方便遍历时的批量处理。
环境准备
- 需要
企业主体App ID
,(个人的可以在开发工具详情中设置勾选不校验webView
,但仅在开发时) - 经ICP备案,域名注册24小时以上
- https:域名的方式
配业务域名
- 首先要在开发管理-中配置业务域名
- 配置业务域名的时候需要下载文件,把下载的文件放置在服务器中前端所在目录
- 放完之后使用
https:域名的方式/文件名.txt
的方式尝试能否访问,如果页面能显示文件内容则成功
代码
web-view
承载网页的容器。会自动铺满整个小程序页面,不能像 iframe
那样能设置某个区域。
<web-view src="http://www.baidu.com/"></web-view>
调试
在模拟器中可以正常访问网站,但是在手机预览中出现白屏,真机调试也是白屏。
预览解决
- 在需要使用
web-view
的目录下的.json
文件下添加"render":webView
, 或手机端小程序右上角三个点打开调试模式,切换至webView
模式。 - 真机调试:切换至2.0调试模式。
详细步骤
小程序端
<web-view src="{{webviewUrl}}" bindmessage="onMessage" />
Page({
onLoad() {
this.webViewContext = wx.createWebViewContext('webviewId', this);
},
onMessage(e) {
const data = e.detail.data;
console.log('收到来自H5的消息:', data);
// 处理消息,必要时回复H5
this.webViewContext.postMessage({ msg: '收到消息了,内容是:' + data.msg });
},
sendMessageToWebView(msg) {
this.webViewContext.postMessage({ msg });
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
注意:wx.createWebViewContext
需要在 web-view
上设置 id="webviewId"
。
H5 (Vue) 页面
<web-view src="{{webUrl}}" bindmessage="getMessage"/>
页面接收小程序消息
// 监听小程序发送消息
window.wx.miniProgram.getEnv((res) => {
if(res.miniprogram){
window.wx.miniProgram.onMessage((data) => {
console.log('接收到小程序消息:', data);
// 这里可调用 Vue 方法或触发事件
});
}
});
2
3
4
5
6
7
8
9
父传子(本地系统传到被嵌入的H5页面)
小程序用url拼接过去,H5页面通过 window.location.href.replace
获取到内容。
//这是H5页面
created() {
// H5获取token const wxobj = {}
window.location.href.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => (wxobj[k] = v))
if ( wxobj.token) {
store.commit( 'user/setToken', wxobj.token)
}
}
2
3
4
5
6
7
8
H5 向小程序发送消息
注意: 在H5系统(被嵌入) 需要安装官方的 weixin-js-sdk
包。
安装
npm add weixin-js-sdk
引入
import wx from "weixin-js-sdk";
使用
wx.miniProgram.postMessage({
data: { token }
});
2
3
function sendMsgToMiniProgram(msg){
if(window.wx && window.wx.miniProgram){
window.wx.miniProgram.postMessage({ msg });
}
}
2
3
4
5
本地系统接收(小程序)
<web-view src="{{webUrl}}" bindmessage="getMessage"/>
Page({
//接收网页数据
getMessage: function (res) {
let token = res.detail.data;
this.setData({ token });
},
})
2
3
4
5
6
7
H5 跳转回小程序
需要用到上面引入的 weixin-js-sdk
包。
const name = '天天'
wx.miniProgram.navigateTo({
url: `/pages/my/my?name=${name}` , // 小程序地址
success () {
console.log('question success')
},
fail (error) {
console.log(error)
}
})
2
3
4
5
6
7
8
9
10
父系统能拿到?后面的传参数
Page({
onLoad(option) {
this.name = JSON.parse(option.name);
},
})
2
3
4
5
关键踩坑点总结
踩坑点 | 解决方案 | 注意事项 |
---|---|---|
wx.createWebViewContext 需要 web-view 指定 id | 小程序 web-view 必须有 id 属性,且与 createWebViewContext 参数一致 | |
H5页面必须引用微信 JS SDK | 确保微信 JS SDK 引入且页面运行在微信环境 | |
监听消息需要确认环境 | 用 getEnv 判断是否在小程序环境,防止报错 | |
postMessage 发送消息格式统一 | 建议都用 JSON 对象结构,避免传输字符串导致解析错误 | |
H5需主动监听小程序消息 | 调用 window.wx.miniProgram.onMessage 实现实时响应 | |
双向异步通信需考虑延时和队列 | 设计消息队列或事件机制保证消息不丢失 |
示例demo结构
- 小程序代码
- page.wxml:
<web-view id="webviewId" src="https://h5.url" bindmessage="onMessage"/>
- page.ts: 处理消息与发送消息
- page.wxml:
- Vue H5代码
- main.ts: 初始化微信环境监听
- 页面组件中调用
wx.miniProgram.postMessage
发送消息 - 监听
onMessage
处理小程序消息
总结
- 只要正确使用微信小程序官方
postMessage
机制,双向通信完全稳定。 - 要点是小程序
web-view
必须带id
,Vue
页面正确引用微信SDK
且监听消息。 - 测试时记得在真机微信环境下,模拟器不支持
web-view
通信。
注意事项
- 微信并不鼓励在小程序中大范围嵌入
H5
,为了避免开发者把小程序变成“浏览器”,微信对小程序与内嵌H5
的通讯做了诸多限制。 - 尽量使用单一方式实现,比如纯小程序原生,将
h5
功能移至小程序原生。 - 原生页面与
H5
之间通过URL
进行通信。 - 不要尝试越过
wx
限制。 - 不得不用混合开发时,尽量做好优化,引入骨架屏等优化方式提高用户体验感。
- 以上三种方式均未很好实现
web-view
与H5
双向通信。 - 在实现小程序与H5的通信时,注意安全性。确保只允许来自可信来源的消息,避免潜在的安全隐患。
处理跨域
由于H5页面可能会遇到跨域问题,确保在H5服务器上设置正确的CORS头部信息,以允许小程序的请求:
Access-Control-Allow-Origin: https://mp.weixin.qq.com
页面缓存
"微信小程序内嵌H5页面缓存问题常常困扰着开发者。为了解决这个问题,可以采取以下几种方法:
- 禁用缓存:在小程序的
webview
组件中,可以通过设置cache-mode
属性为no-cache
来禁用缓存。这样可以确保每次打开webview
时都会重新加载页面,而不使用缓存。 - 动态添加时间戳:在向H5页面发起请求时,可以在URL参数中添加一个随机的时间戳参数,以确保每次请求的URL都是唯一的。这样可以绕过浏览器的缓存机制,强制浏览器重新请求页面内容。
- 使用localStorage:在H5页面中,可以利用
localStorage
来存储一些静态资源,以减少对服务器的请求。在小程序内嵌的H5页面中,可以通过localStorage
来实现一定程度的缓存。 - 监听webview事件:可以通过监听
webview
的事件,如load
事件和error
事件,来动态控制页面的缓存策略。例如,可以在load事件触发时清除缓存,以确保每次都是最新的页面内容。 - 与后端协作:在H5页面的后端服务器上,可以设置响应头中的缓存控制字段,如
Cache-Control
和Expires
,来指示浏览器不缓存页面内容。这样可以在一定程度上解决缓存问题。
通过以上方法,可以有效地解决微信小程序 webview
内嵌H5页面的缓存问题,确保用户能够获得最新的页面内容,提升用户体验。"