<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        微信小程序webview與h5通過postMessage實現實時通訊的實現

        來源:懂視網 責編:小采 時間:2020-11-27 21:52:05
        文檔

        微信小程序webview與h5通過postMessage實現實時通訊的實現

        微信小程序webview與h5通過postMessage實現實時通訊的實現:在做 React Native 應用時,如果需要在 App 里面內嵌 H5 頁面,那么 H5 與 App 之間可以通過 Webview 的 PostMessage 功能實現實時的通訊,但是在小程序里面,雖然也提供了一個 webview 組件,但是,在進行 postMessage 通訊時,官方文檔里面給
        推薦度:
        導讀微信小程序webview與h5通過postMessage實現實時通訊的實現:在做 React Native 應用時,如果需要在 App 里面內嵌 H5 頁面,那么 H5 與 App 之間可以通過 Webview 的 PostMessage 功能實現實時的通訊,但是在小程序里面,雖然也提供了一個 webview 組件,但是,在進行 postMessage 通訊時,官方文檔里面給

        在做 React Native 應用時,如果需要在 App 里面內嵌 H5 頁面,那么 H5 與 App 之間可以通過 Webview 的 PostMessage 功能實現實時的通訊,但是在小程序里面,雖然也提供了一個 webview 組件,但是,在進行 postMessage 通訊時,官方文檔里面給出了一條很變態的說明:

        網頁向小程序 postMessage 時,會在特定時機(小程序后退、組件銷毀、分享)觸發并收到消息。e.detail = { data },data 是多次 postMessage 的參數組成的數組
        這里面已經說的很明白了,不管我們從 H5 頁面里面 postMessage 多少次,小程序都是收不到的,除非:

        1. 用戶做了回退到上一頁的操作
        2. 組件銷毀
        3. 用戶點擊了分享

        這里面其實我沒有完全說對,官方其實說的是 小程序后退,并沒有說是用戶做回退操作,經過我的實測,確實人家表達得很清楚了,我們通過微信官方的SDK調起的回退也是完全可行的:

        wx.miniProgram.navigateBack()

        大體思路

        從上面的分析和實測中我們可以知道,要實現無需要用戶操作即可完成的通訊,第三種情況我們是完全不需要考慮了的,那么來仔細考慮第 1 和第 2 種場景。

        第 1 種方式:回退

        當我們想通過網頁向小程序發送數據,同時還可以回退到上一個頁面時,我們可以在 wx.miniProgram.postMessage 之后,立馬調用一次 wx.miniProgram.navigateBack(),此時小程序的操作是:

        1. 處理 postMessage 信息
        2. 回退到上一頁

        我們在處理 postMessage 的時候做一些特殊操作,可以將這些數據保存下來

        第 2 種方式:組件銷毀

        這是我感覺最合適的一種方式,可以讓小程序拿到數據,同時還保留在當前頁面,只需要銷毀一次 webview 即可,大概的流程就是:

        1. 小程序 postMessage
        2. 小程序 navigateTo 將小程序頁面導向一個特殊的頁面
        3. 小程序的那個特殊頁面立馬回退到 webview 所在的頁面
        4. webview 所在的頁面的 onShow 里面,做一次處理,將 webview 銷毀,然后再次打開
        5. 觸發 onMessage 拿到數據
        6. H5 頁面再次被打開

        這種方式雖然變態,但是至少可以做到實時拿到數據,同時還保留在當前 H5 頁面,唯一需要解決的是,在做這整套操作前,H5 頁面需要做好狀態的緩存,要不然,再次打開之后,H5 的數據就清空了。

        第 1 種方式:通過回退,將數據提交給小程序之后傳遞給 webview 的上一頁面

        這種方式實現起來其實是很簡單的,我們現在新建兩個頁面:

        sandbox/canvas-by-webapp/index.js

        const app = getApp();
        
        Page({
         data: {
         url: '',
         dimension: null,
         mime: '',
         },
         handleSaveTap: function() {
         wx.navigateTo({
         url: '/apps/browser/index',
         events: {
         receiveData: data => {
         console.log('receiveData from web browser: ', data);
         if (typeof data === 'object') {
         const { url, mime, dimension } = data;
         if (url && mime && dimension) {
         this.setData({
         url,
         dimension,
         mime,
         });
        
         this.save(data);
         }
         }
         }
         }
         })
         },
        
         save: async function({ url, mime, dimension }) {
         try {
         await app.saveImages([url]);
         app.toast('保存成功!');
         } catch (error) {
         console.log(error);
         app.toast(error.message || error);
         }
         },
        });
        
        

        上面的代碼中,核心點,就在于 wx.navigateTo 調用時,里面的 events 參數,這是用來進行與 /apps/browser/index 頁面通訊,接收數據用的。

        apps/browser/index.js

        我省略了絕大多數與本文無關的代碼,保存最主要的三個:

        Page({
         onLoad() {
         if (this.getOpenerEventChannel) {
         this.eventChannel = this.getOpenerEventChannel();
         }
         },
         handleMessage: function(message) {
         const { action, data } = message;
         if (action === 'postData') {
         if (this.eventChannel) {
         this.eventChannel.emit('receiveData', data);
         }
         }
         },
        
         handlePostMessage: function(e) {
         const { data } = e.detail;
         if (Array.isArray(data)) {
         const messages = data.map(item => {
         try {
         const object = JSON.parse(item);
         this.handleMessage(object);
         return object;
         } catch (error) {
         return item;
         }
         });
        
         this.setData({
         messages: [...messages],
         });
         }
         },
        })
        
        

        其實,onLoad 方法中,我們使用了自微信 SDK 2.7.3 版本開始提供的 getOpenerEventChannel 方法,它可以創建一個與上一個頁面的事件通訊通道,這個我們會在 handleMessage 中使用。

        handlePostMessage 就是被 bindmessage 至 webview 上面的方法,它用于處理從 H5 頁面中 postMessage 過來的消息,由于小程序是將多次 postMessage 的消息放在一起發送過來的,所以,與其它的Webview不同點在于,我們拿到的是一個數組: e.detail.data, handlePostMessage 的作用就是遍歷這個數組,取出每一條消息,然后交由 handleMessage 處理。

        handleMessage 在拿到 message 對象之后,將 message.action 與 message.data 取出來(*這里需要注意,這是我們在 H5 里面的設計的一種數據結構,你完全可以在自己的項目中設計自己的結構),根據 action 作不同的操作,我在這里面的處理是,當 action === 'postData' 時,就通過 getOpenerEventChannel 得到的消息通道 this.eventChannel 將數據推送給上一級頁面,也就是 /sandbox/canvas-by-webapp,但是不需要自己執行 navigateBack ,因為這個需要交由 H5 頁面去執行。

        H5 頁面的實現

        我的 H5 主要就是使用 html2canvas 庫生成 Canvas 圖(沒辦法,自己在小程序里面畫太麻煩了),但是這個不在本文討論過程中,我們就當是已經生成了 canvas 圖片了,將其轉為 base64 文本了,然后像下面這樣做:

        wx.miniProgram.postMessage({
         data: JSON.stringify({
         action: 'postData',
         data: 'BASE 64 IMAGE STRING'
         })
        });
        
        wx.miniProgram.navigateBack()
        
        

        將數據 postMessage 之后,立即 navigateBack() ,來觸發一次回退,也就觸發了 bindmessage 事件。

        使用銷毀 webview 實現實時通訊
        接下來,咱就開始本文的重點了,比較變態的方式,但是也沒想到更好的辦法,所以,大家將就著交流吧。

        H5 頁面的改變

        wx.miniProgram.postMessage({
         data: JSON.stringify({
         action: 'postData',
         data: 'BASE 64 IMAGE STRING'
         })
        });
        
        wx.miniProgram.navigateTo('/apps/browser/placeholder');
        

        H5 頁面只是將 wx.miniProgram.navigateBack() 改成了 wx.miniProgram.navigateTo('/apps/browser/placeholder') ,其它的事情就先都交由小程序處理了。

        /apps/browser/placeholder

        這個頁面的功能其實很簡單,當打開它了之后,做一點點小操作,立馬回退到上一個頁面(就是 webview 所在的頁面。

        Page({
         data: { loading: true },
         onLoad(options) {
        
         const pages = getCurrentPages();
        
         const webviewPage = pages[pages.length - 2];
        
         webviewPage.setData(
         {
         shouldReattachWebview: true
         },
         () => {
         app.wechat.navigateBack();
         }
         );
         },
        });
        
        

        我們一行一行來看:

        const pages = getCurrentPages();

        這個可以拿到當前整個小程序的頁面棧,由于這個頁面我們只允許從小程序的 Webview 頁面過來,所以,它的上一個頁面一定是 webview 所在的頁面:

        const webviewPage = pages[pages.length - 2];

        拿到 webviewPage 這個頁面對象之后,調用它的方法 setData 更新一個值:

         webviewPage.setData(
         {
         shouldReattachWebview: true
         },
         () => {
         app.wechat.navigateBack();
         }
         );
        

        shouldReattachWebview 這個值為 true 的時候,表示需要重新 attach 一次 webview,這個頁面的事件現在已經做完了,回到 webview 所在的頁面

        apps/browser/index.js 頁面

        我同樣只保留最核心的代碼,具體的邏輯,我就直接寫進代碼里面了。

        Page({
         data: {
         shouldReattachWebview: false, // 是否需要重新 attach 一次 webview 組件
         webviewReattached: false, // 是否已經 attach 過一次 webview 了
         hideWebview: false // 是否隱藏 webview 組件
         },
         onShow() {
         // 如果 webview 需要重新 attach 
         if (this.data.shouldReattachWebview) {
         this.setData(
         {
         // 隱藏 webview
         hideWebview: true,
         },
         () => {
         this.setData(
         {
         // 隱藏之后立馬顯示它,此時完成一次 webview 的銷毀,拿到了 postMessage 中的數據
         hideWebview: false,
         webviewReattached: true,
         },
         () => {
         // 拿到數據之后,處理 canvasData
         this.handleCanvasData();
         }
         );
         }
         );
         }
         },
         // 當 webview 被銷毀時,該方法被觸發
         handlePostMessage: function(e) {
         const { data } = e.detail;
         if (Array.isArray(data)) {
         const messages = data.map(item => {
         try {
         const object = JSON.parse(item);
         this.handleMessage(object);
         return object;
         } catch (error) {
         return item;
         }
         });
        
         this.setData({
         messages: [...messages],
         });
         }
         },
         // 處理每一條消息
         handleMessage: function(message) {
         const {action, data} = message
         // 如果 saveCanvas action
         if (action === 'saveCanvas') {
         // 將數據先緩存進 Snap 中
         const { canvasData } = this.data;
         // app.checksum 是我自己封裝的方法,計算任何數據的 checksum,我拿它來當作 key
         // 這可以保證同一條數據只會被處理一次
         const snapKey = app.checksum(data);
         // 只要未處理過的數據,才需要再次數據
         if (canvasData[snapKey] !== true) {
         if (canvasData[snapKey] === undefined) {
         // 將數據從緩存進 `snap` 中
         // 這也是我自己封裝的一個方法,可以將數據緩存起來,并且只能被讀取一次
         app.snap(snapKey, data);
         // 設置 canvasData 中 snapKey 字段為 `false`
         canvasData[snapKey] = false;
         this.setData({
         canvasData,
         });
         }
         }
         }
         },
         // 當 webview 被重新 attach 之后,canvas 數據已經被保存進 snap 中了,
         handleCanvasData: async function handleCanvasData() {
         const { canvasData } = this.data;
         // 從 canvasData 中拿到所有的 key,并過濾到已經處理過的數據
         const keys = Object.keys(canvasData).filter(key => canvasData[key] === false);
        
         if (keys.length === 0) {
         return;
         }
        
         for (let i = 0; i < keys.length; i += 1) {
         try {
         const key = keys[i];
         const { url } = app.snap(key);
         // 通過自己封裝的方法,將 url(也就是Base64字符)保存至相冊
         const saved = await app.saveImages(url);
         // 更新 canvasData 對象
         canvasData[key] = true
         this.setData({
         canvasData
         })
         console.log('saved: ', saved);
         } catch (error) {
         app.toast(error.message);
         return;
         }
         }
         },
        })
        
        

        對應的 index.wxml 文件內容如下:

        <web-view src="{{src}}" wx:if="{{src}}" bindmessage="handlePostMessage" wx:if="{{!hideWebview}}" />

        流程回顧與總結

        1. 打開 webview 頁面,打開 h5
        2. h5 頁面生成 canvas 圖,并轉為 base64 字符
        3. 通過 wx.miniProgram.postMessage 將 base64 發送給小程序
        4. 調用 wx.miniProgram.navigateTo 將頁面導向一個特殊頁面
        5. 在特殊頁面中,將 webview 所在頁面的 shouldReattachWebview 設置為 true
        6. 在特殊頁面中回退至 webview 所在頁面
        7. webview 所在頁面的 onShow 事件被觸發
        8. 在 onShow 事件檢測 shouldReattachWebview 是否為 true,若為 true
        9. 將 hideWebview 設置為 true,引起 web-view 組件的銷毀
        10. handlePostMessage 被觸發,解析所有的 message 之后交給 handleMessage 逐條處理
        11. handleMessage 發現 action === 'saveCanvas' 的事件,拿到 data
        12. 根據 data 計算 checksum ,以 checksum 為 key 緩存下來數據,并將這個 checksum 保存到 canvasData 對象中
        13. 此時 hideWebview 被 onShow 里面 setData 的回調中的 setData 重新置為 false,web-view 重新加 attach,H5頁面重新加載
        14. webview 重新 attach 之后, this.handleCanvasData 被觸發,
        15. handleCanvasData 檢測是否有需要保存的 canvas 數據,如果有,保存,修改 canvasData 狀態

        整個流程看舊去很繁瑣,但是寫起來其實還好,這里面最主要的是需要注意,數據去重,微信的 postMessage 里面拿到的永遠 都是 H5 頁面從被打開到關閉的所有數據。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        微信小程序webview與h5通過postMessage實現實時通訊的實現

        微信小程序webview與h5通過postMessage實現實時通訊的實現:在做 React Native 應用時,如果需要在 App 里面內嵌 H5 頁面,那么 H5 與 App 之間可以通過 Webview 的 PostMessage 功能實現實時的通訊,但是在小程序里面,雖然也提供了一個 webview 組件,但是,在進行 postMessage 通訊時,官方文檔里面給
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲AV无码成人专区| 亚洲av无码专区青青草原| 亚洲免费网站观看视频| 久久免费国产精品一区二区| 日韩午夜免费视频| 亚洲国产日韩精品| 亚洲人成网站在线在线观看| 可以免费观看的国产视频| 亚洲精品无码永久在线观看| 亚洲男同gay片| 国产精品黄页在线播放免费| 亚洲色丰满少妇高潮18p| 一级一级毛片免费播放| 日韩免费视频一区二区| 国外成人免费高清激情视频| 国产成人精品久久亚洲高清不卡 | 亚洲欧好州第一的日产suv| 成年女人毛片免费播放人| 精品亚洲AV无码一区二区| 在线视频精品免费| 久久国产成人亚洲精品影院| 亚洲美女视频网站| 国产亚洲精品国产福利在线观看| AV免费网址在线观看| 久久亚洲国产午夜精品理论片| 成人免费网站久久久| 亚洲人AV永久一区二区三区久久| 一级毛片在播放免费| 亚洲自偷自偷偷色无码中文| 亚洲爆乳精品无码一区二区| 99热这里只有精品免费播放| 亚洲va中文字幕无码| 亚洲一区二区三区播放在线| 国产99视频精品免费观看7| 亚洲永久精品ww47| 久久狠狠躁免费观看| 亚洲日本视频在线观看| 在线免费观看视频你懂的| 黄网站在线播放视频免费观看| 亚洲熟妇无码乱子AV电影| 一级毛片成人免费看免费不卡|