微信小程序webview?postmessage通信完整配置和使用
需求概述
在微信小程序中使用 web-view 組件與內(nèi)嵌網(wǎng)頁(yè)進(jìn)行雙向通信,主要通過 postMessage 實(shí)現(xiàn)。以下是完整的配置和使用方法:
通信指南
1. 基礎(chǔ)配置
小程序端配置
// app.json 或 page.json
{
"usingComponents": {},
"permission": {
"scope.webView": {
"desc": "用于網(wǎng)頁(yè)和小程序通信"
}
}
}網(wǎng)頁(yè)端配置
<!-- 內(nèi)嵌網(wǎng)頁(yè)需引入微信JS-SDK --> <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> <!-- 或使用官方最新版本 -->
2. 通信實(shí)現(xiàn)
方案一:小程序向網(wǎng)頁(yè)發(fā)送消息
小程序端代碼:
// page.js
Page({
data: {
webViewUrl: 'https://your-domain.com/page.html'
},
onLoad() {
// 通過 web-view 組件的 ref 發(fā)送消息
},
// 向網(wǎng)頁(yè)發(fā)送消息
sendToWebPage() {
const webview = this.selectComponent('#myWebview')
webview.postMessage({
data: {
type: 'from_miniprogram',
message: 'Hello from Mini Program!',
timestamp: Date.now()
}
})
},
// 接收網(wǎng)頁(yè)消息
onMessage(e) {
console.log('收到網(wǎng)頁(yè)消息:', e.detail.data)
// 處理網(wǎng)頁(yè)發(fā)送的數(shù)據(jù)
const { type, data } = e.detail.data
if (type === 'from_web') {
// 處理邏輯
}
}
})<!-- page.wxml -->
<web-view
id="myWebview"
src="{{webViewUrl}}"
bindmessage="onMessage"
bindload="onWebViewLoad"
/>
<button bindtap="sendToWebPage">發(fā)送消息到網(wǎng)頁(yè)</button>網(wǎng)頁(yè)端代碼:
// 監(jiān)聽小程序消息
document.addEventListener('message', function(e) {
const data = e.data
console.log('收到小程序消息:', data)
// 處理消息
if (data.type === 'from_miniprogram') {
// 執(zhí)行相應(yīng)操作
// 回復(fù)消息給小程序
if (window.wx && window.wx.miniProgram) {
window.wx.miniProgram.postMessage({
data: {
type: 'from_web',
reply: 'Message received!',
original: data.message
}
})
}
}
})
// 主動(dòng)發(fā)送消息到小程序
function sendToMiniProgram() {
if (window.wx && window.wx.miniProgram) {
window.wx.miniProgram.postMessage({
data: {
type: 'user_action',
action: 'button_click',
value: 'some_value',
timestamp: new Date().getTime()
}
})
}
}3. 完整通信示例
雙向通信封裝
小程序端封裝:
// utils/webviewBridge.js
class WebViewBridge {
constructor(webviewRef) {
this.webview = webviewRef
this.messageHandlers = new Map()
}
// 發(fā)送消息到網(wǎng)頁(yè)
postMessage(type, data) {
if (!this.webview) return false
this.webview.postMessage({
data: {
type,
payload: data,
timestamp: Date.now(),
source: 'miniprogram'
}
})
return true
}
// 注冊(cè)消息處理器
onMessage(type, handler) {
this.messageHandlers.set(type, handler)
}
// 處理接收到的消息
handleMessage(event) {
const { type, payload, source } = event.detail.data
if (source === 'web') {
const handler = this.messageHandlers.get(type)
if (handler) {
handler(payload)
}
}
}
// 移除處理器
offMessage(type) {
this.messageHandlers.delete(type)
}
}
export default WebViewBridge網(wǎng)頁(yè)端封裝:
// webview-bridge.js
class MiniProgramBridge {
constructor() {
this.handlers = new Map()
this.init()
}
init() {
// 監(jiān)聽小程序消息
document.addEventListener('message', (e) => {
const { type, payload, source } = e.data
if (source === 'miniprogram') {
this.dispatch(type, payload)
}
})
// 監(jiān)聽頁(yè)面卸載
window.addEventListener('beforeunload', () => {
this.postMessage('page_unload', {})
})
}
// 發(fā)送消息到小程序
postMessage(type, data) {
if (window.wx && window.wx.miniProgram) {
window.wx.miniProgram.postMessage({
data: {
type,
payload: data,
timestamp: Date.now(),
source: 'web'
}
})
return true
}
return false
}
// 注冊(cè)消息處理器
on(type, handler) {
if (!this.handlers.has(type)) {
this.handlers.set(type, [])
}
this.handlers.get(type).push(handler)
}
// 分發(fā)消息
dispatch(type, data) {
const typeHandlers = this.handlers.get(type)
if (typeHandlers) {
typeHandlers.forEach(handler => handler(data))
}
}
// 移除處理器
off(type, handler) {
const typeHandlers = this.handlers.get(type)
if (typeHandlers) {
const index = typeHandlers.indexOf(handler)
if (index > -1) {
typeHandlers.splice(index, 1)
}
}
}
}
// 創(chuàng)建全局實(shí)例
window.MiniProgramBridge = new MiniProgramBridge()4. 使用示例
小程序頁(yè)面使用:
import WebViewBridge from '../../utils/webviewBridge'
Page({
data: {
url: 'https://example.com'
},
onLoad() {
// 在 web-view 加載完成后初始化
},
onWebViewLoad() {
const webview = this.selectComponent('#webview')
this.bridge = new WebViewBridge(webview)
// 注冊(cè)消息處理器
this.bridge.onMessage('user_login', (data) => {
console.log('用戶登錄:', data)
// 處理登錄邏輯
})
this.bridge.onMessage('payment_success', (data) => {
console.log('支付成功:', data)
wx.showToast({
title: '支付成功'
})
})
},
// 發(fā)送用戶信息到網(wǎng)頁(yè)
sendUserInfo() {
this.bridge.postMessage('user_info', {
userId: '123',
nickname: '張三',
avatar: 'url'
})
}
})網(wǎng)頁(yè)端使用:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<button onclick="sendMessage()">發(fā)送消息到小程序</button>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="webview-bridge.js"></script>
<script>
// 監(jiān)聽小程序消息
MiniProgramBridge.on('user_info', (data) => {
console.log('收到用戶信息:', data)
document.getElementById('user-name').innerText = data.nickname
})
// 發(fā)送消息到小程序
function sendMessage() {
MiniProgramBridge.postMessage('button_click', {
buttonId: 'submit',
value: 'confirmed'
})
}
// 頁(yè)面加載完成通知小程序
window.addEventListener('load', () => {
MiniProgramBridge.postMessage('page_loaded', {
title: document.title,
url: window.location.href
})
})
</script>
</body>
</html>5. 最佳實(shí)踐
// 1. 添加消息類型常量
const MessageTypes = {
USER_INFO: 'user_info',
PAYMENT: 'payment',
NAVIGATION: 'navigation',
ERROR: 'error'
}
// 2. 添加超時(shí)處理
function postMessageWithTimeout(type, data, timeout = 5000) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error('Message timeout'))
}, timeout)
// 發(fā)送消息邏輯
})
}
// 3. 錯(cuò)誤處理
try {
webview.postMessage(data)
} catch (error) {
console.error('發(fā)送消息失敗:', error)
// 重試或降級(jí)處理
}6. 注意事項(xiàng)
1.確保網(wǎng)頁(yè)域名已在小程序后臺(tái)配置
2.處于安全性的考慮,始終驗(yàn)證接收到的數(shù)據(jù),并且避免執(zhí)行不可信的腳本,防止xss攻擊
3.避免高頻發(fā)送(>100條/秒)
4.確保網(wǎng)頁(yè)端微信JS-SDK版本兼容
5.微信小程序 WebView 的 bindmessage 事件有一個(gè)延遲觸發(fā)機(jī)制,網(wǎng)頁(yè)向小程序發(fā)送的消息不會(huì)立即觸發(fā) bindmessage,而是在特定時(shí)機(jī)批量觸發(fā)。網(wǎng)頁(yè)向小程序 postMessage 時(shí),會(huì)在以下特定時(shí)機(jī)觸發(fā)并收到消息:小程序后退、組件銷毀、分享、復(fù)制鏈接。e.detail = { data },data是多次 postMessage 的參數(shù)組成的數(shù)組。微信小程序webview官方文檔
7.實(shí)時(shí)通信方案
最佳實(shí)踐:對(duì)于需要實(shí)時(shí)通信的場(chǎng)景,應(yīng)該使用 WebSocket、URL 參數(shù)、Storage 輪詢等替代方案,bindmessage 更適合作為最終的數(shù)據(jù)提交機(jī)制。
// 方案1:使用URL參數(shù)傳遞狀態(tài)(實(shí)時(shí))
// 網(wǎng)頁(yè)端
function updateState(state) {
// 通過修改hash或reload傳遞數(shù)據(jù)
window.location.hash = 'state=' + encodeURIComponent(JSON.stringify(state))
// 或者使用URL參數(shù)
const newUrl = window.location.pathname + '?data=' + encodeURIComponent(JSON.stringify(state))
window.history.replaceState({}, '', newUrl)
}
// 方案2:使用Storage同步(需要輪詢)
// 網(wǎng)頁(yè)端
function sendViaStorage(data) {
localStorage.setItem('web_to_miniprogram', JSON.stringify({
data,
timestamp: Date.now()
}))
}
// 小程序端(需要輪詢)
setInterval(() => {
const storage = wx.getStorageSync('web_to_miniprogram')
if (storage) {
this.handleMessage(storage.data)
wx.removeStorageSync('web_to_miniprogram')
}
}, 100)
// 方案3:使用WebSocket(真正實(shí)時(shí))
const ws = new WebSocket('wss://your-server.com')
ws.onmessage = (e) => {
// 小程序通過后端中轉(zhuǎn)消息
}使用URL 參數(shù)為什么能達(dá)到實(shí)時(shí)的效果?
使用 URL 參數(shù) 可以達(dá)到實(shí)時(shí)效果,是因?yàn)?WebView 的 URL 變化會(huì)立即觸發(fā)小程序端的 bindload 事件(頁(yè)面加載或重載),而 bindload 是實(shí)時(shí)觸發(fā)的。這與 bindmessage 的延遲觸發(fā)機(jī)制完全不同。
拓展
什么是webview?它的作用是什么?
WebView(網(wǎng)頁(yè)視圖)可以簡(jiǎn)單理解為一個(gè)嵌入在應(yīng)用程序(App或者小程序)內(nèi)部的“瀏覽器”。它不是一個(gè)獨(dú)立的瀏覽器(如 Chrome 或 Safari),而是一個(gè)讓 App或者小程序 能夠顯示和處理網(wǎng)頁(yè)內(nèi)容的控件或組件。
webview是“原生”與“網(wǎng)頁(yè)”的結(jié)合體
在移動(dòng)和桌面應(yīng)用開發(fā)中,通常有兩種開發(fā)方式:
- 原生開發(fā) (Native): 為特定平臺(tái)(如 iOS、Android或者小程序)專門編寫的代碼,性能最好,但開發(fā)成本高。
- Web 開發(fā): 使用 HTML、CSS 和 JavaScript 編寫的網(wǎng)頁(yè),跨平臺(tái)能力強(qiáng),但性能相對(duì)較弱。
WebView 處于兩者之間。它允許開發(fā)者在原生 App或者小程序 中嵌入網(wǎng)頁(yè)內(nèi)容。例如,你在一個(gè)電商 App 里看到的商品詳情頁(yè),其實(shí)可能就是一個(gè)加載了網(wǎng)頁(yè)的 WebView,而不是用原生代碼畫出來的界面。
WebView 的作用非常廣泛,主要體現(xiàn)在以下幾個(gè)方面:
實(shí)現(xiàn)混合式開發(fā) (Hybrid Development)
這是 WebView 最主要的作用。很多 App或者小程序的頁(yè)面并不是完全用原生代碼寫的,而是部分界面使用 WebView 加載網(wǎng)頁(yè)。
- 優(yōu)勢(shì): 開發(fā)者可以使用一套網(wǎng)頁(yè)代碼(HTML/JS),同時(shí)在 Android 和 iOS 或者小程序上運(yùn)行,大大降低了開發(fā)和維護(hù)成本。
- 常見框架: 像 uni-app、React Native 等框架底層都利用了 WebView 技術(shù)。
動(dòng)態(tài)更新,無需發(fā)版
這是 WebView 相比原生代碼的巨大優(yōu)勢(shì)。
- 原生 App或者小程序: 如果想修改界面或邏輯,必須修改代碼 -> 重新打包 -> 提交平臺(tái)審核 -> 用戶下載更新。
- WebView: 只需要在服務(wù)器端更新網(wǎng)頁(yè)代碼(HTML/JS),下次用戶打開頁(yè)面時(shí),看到的就是最新的內(nèi)容,用戶無需重新下載安裝 App。這非常適合需要頻繁更新活動(dòng)頁(yè)面(如促銷、廣告頁(yè))的場(chǎng)景。
強(qiáng)大的交互能力
WebView 不僅僅是一個(gè)“看”網(wǎng)頁(yè)的工具,它還能和原生系統(tǒng)進(jìn)行深度交互(Native-Web 互操作):
- 調(diào)用系統(tǒng)功能: 網(wǎng)頁(yè)可以通過 WebView 調(diào)用手機(jī)的攝像頭、相冊(cè)、地理位置(GPS)等原生功能。
- 數(shù)據(jù)互通: 原生代碼可以往網(wǎng)頁(yè)里傳數(shù)據(jù),網(wǎng)頁(yè)也可以把用戶操作的結(jié)果回傳給原生代碼。
跨平臺(tái)兼容
在 Windows、macOS、Android、iOS 等不同平臺(tái)上,WebView 都能提供一致的網(wǎng)頁(yè)渲染體驗(yàn)。例如,Microsoft Edge WebView2 控件允許開發(fā)者在桌面應(yīng)用中使用最新的 Chromium 引擎渲染網(wǎng)頁(yè)。
簡(jiǎn)單來說,WebView 就是 App 里的一個(gè)“窗口”,用來展示網(wǎng)頁(yè)內(nèi)容。它的核心價(jià)值在于:讓 App 既能擁有原生的系統(tǒng)權(quán)限和性能,又能具備網(wǎng)頁(yè)的靈活更新和跨平臺(tái)能力。你在日常使用 App 時(shí),那些偶爾需要“加載”的頁(yè)面,或者下拉刷新就能看到新內(nèi)容的界面,很大概率都是 WebView 在背后工作。
總結(jié)
到此這篇關(guān)于微信小程序webview postmessage通信完整配置和使用的文章就介紹到這了,更多相關(guān)微信小程序webview postmessage通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript實(shí)現(xiàn)json頁(yè)面分頁(yè)實(shí)例代碼
這篇文章主要介紹了javascript實(shí)現(xiàn)json頁(yè)面分頁(yè)實(shí)例代碼,需要的朋友可以參考下2014-02-02
JavaScript中事件流冒泡的原理與實(shí)現(xiàn)
在JavaScript中,事件流冒泡是一種非常重要的概念,它是指事件從最內(nèi)層的元素開始,逐級(jí)向外傳播到最外層元素的過程,下面我們就來了解下JavaScript中事件流冒泡的原理與實(shí)現(xiàn)吧2023-11-11
bootstrap日期插件daterangepicker使用詳解
這篇文章主要為大家詳細(xì)介紹了bootstrap日期插件daterangepicker的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
JavaScript實(shí)現(xiàn)前端倒計(jì)時(shí)效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)前端倒計(jì)時(shí)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-02-02
JS時(shí)間戳與日期格式互相轉(zhuǎn)換的簡(jiǎn)單方法示例
這篇文章主要給大家介紹了關(guān)于JS時(shí)間戳與日期格式互相轉(zhuǎn)換的簡(jiǎn)單方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
javascript定義變量時(shí)帶var與不帶var的區(qū)別分析
這篇文章主要介紹了javascript定義變量時(shí)帶var與不帶var的區(qū)別,以一個(gè)簡(jiǎn)單實(shí)例分析了變量定義時(shí)帶var與不帶var的執(zhí)行原理及用法區(qū)別,需要的朋友可以參考下2015-01-01
純JavaScript實(shí)現(xiàn)實(shí)時(shí)反饋系統(tǒng)時(shí)間
這篇文章主要介紹了純JavaScript實(shí)現(xiàn)實(shí)時(shí)反饋系統(tǒng)時(shí)間的相關(guān)資料,需要的朋友可以參考下2017-10-10

