????????首先,微信小程序向web-view傳遞數(shù)據(jù)一般通過地址欄傳參的形式(給src賦值或者修改hash),這樣一般就已經(jīng)能夠滿足實際開發(fā)需求了,所以這里主要探討web-view向微信小程序傳參。下面,我們從官方文檔入手,基于web-view標(biāo)簽自身的能力特點做一些嘗試:
一、JSSDK提供的wx.miniProgram.postMessage
????????文檔中說此方法只能在“小程序后退、組件銷毀、分享、復(fù)制鏈接”時才會觸發(fā),意思也就是說通信不是即時的,而實際中,我們大多是需要即時通信的,所以該方法的用處有限。
// h5頁面
wx.miniProgram.postMessage({data: 'foo' })
wx.miniProgram.postMessage({data: {foo: 'bar'} })
// 小程序
<web-view src="{{url}}" bindmessage="messageHandler"></web-view>

二、路由跳轉(zhuǎn)(wx.miniProgram.navigateTo/redirectTo等)
????????文檔提供了一些web-view改變小程序路由的方法,那么能否通過這些方法傳遞數(shù)據(jù),然后在小程序中攔截路由,拿到數(shù)據(jù)后再阻止跳轉(zhuǎn)?答案是不行。原因是:小程序雖然可以通過wx.onAppRoute監(jiān)聽路由變更,但不能阻止路由跳轉(zhuǎn)行為。
????????另外,即便是當(dāng)前頁面跳轉(zhuǎn)到當(dāng)前頁面也不行(即/page/webview/index跳轉(zhuǎn)到/page/webview/index?a=123),頁面會重新加載,閃現(xiàn)白屏。

三、事件綁定bindload
????????web-view標(biāo)簽提供了3個事件:bindload、bindmessage、binderror。其中,bindmessage是配合上面的postMessage使用的;binderror是網(wǎng)頁加載失敗時觸發(fā)的;只有bindload(頁面加載成功時觸發(fā))存在可利用的契機。
? ??????3.1 在h5頁面中修改location.href,通過地址欄向小程序傳參

????????這是最直接能想到的辦法,H5頁面不復(fù)雜的話,用戶幾乎感覺不到頁面重新加載帶來的影響。不過,該方式隱性要求我們:在開發(fā)時,最好將H5頁面設(shè)計成“頁面的所有狀態(tài)都使用地址欄參數(shù)和localStorage來維護”,這樣,無論是“小程序變更h5頁面”還是“h5頁面向小程序傳遞自身當(dāng)前的狀態(tài)”都會很方便。
? ??????3.2 是否可以模擬觸發(fā)load事件來優(yōu)化上述方式(fail)
????????答案是不行的。假如是在h5頁面內(nèi),模擬觸發(fā)load事件是可行的,但是網(wǎng)頁內(nèi)window的load并不會冒泡給web-view標(biāo)簽。

? ??????3.3 是否可以使用多標(biāo)簽來優(yōu)化上述方式(fail)
????????現(xiàn)在的瀏覽器都支持多標(biāo)簽頁,那么web-view標(biāo)簽是否也可以同時打開兩個標(biāo)簽頁(頁面a、頁面b),其中頁面a用來展示頁面,頁面b(假設(shè)它是頁面a用window.open(‘page-b’, ‘_blank’)打開的)則不顯示;需要傳參時,頁面a修改頁面b的地址,繼而觸發(fā)load事件,將參數(shù)傳遞給小程序?
????????答案是不行的。
????????雖然window.open方法可以執(zhí)行,但貌似在web-view中,“_blank”跟“_self”一樣,無論是頁面a操作頁面b,還是頁面b操作頁面a都操作的是同一個標(biāo)簽頁。
? ??????3.4 是否可使用history.pushState/replaceState或修改hash來觸發(fā)load(fail)
????????答案是不行的。畢竟這兩種方法都只是修改地址,并不影響網(wǎng)頁內(nèi)容,而load是需要網(wǎng)頁加載才可能觸發(fā)。
四、Websocket通信
????????小程序和H5網(wǎng)頁通過websocket服務(wù)器進行通信,這種方式固然很好,但需要額外成本,此處不作考慮。