午夜无码人妻aⅴ大片色欲张津瑜,国产69久久久欧美黑人A片,色妺妺视频网,久久久久国产综合AV天堂

微信小程序webview與h5通過postMessage實(shí)現(xiàn)實(shí)時通訊的示例分析

這篇文章給大家分享的是有關(guān)微信小程序webview與h5通過postMessage實(shí)現(xiàn)實(shí)時通訊的示例分析的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

10年積累的成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有馬關(guān)免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

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

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

  1. 用戶做了回退到上一頁的操作

  2. 組件銷毀

  3. 用戶點(diǎn)擊了分享

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

wx.miniProgram.navigateBack()

大體思路

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

第 1 種方式:回退

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

  1. 處理 postMessage 信息

  2. 回退到上一頁

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

第 2 種方式:組件銷毀

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

  1. 小程序 postMessage

  2. 小程序 navigateTo 將小程序頁面導(dǎo)向一個特殊的頁面

  3. 小程序的那個特殊頁面立馬回退到 webview 所在的頁面

  4. webview 所在的頁面的 onShow 里面,做一次處理,將 webview 銷毀,然后再次打開

  5. 觸發(fā) onMessage 拿到數(shù)據(jù)

  6. H5 頁面再次被打開

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

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

這種方式實(shí)現(xiàn)起來其實(shí)是很簡單的,我們現(xiàn)在新建兩個頁面:

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);
  }
 },
});

上面的代碼中,核心點(diǎn),就在于 wx.navigateTo 調(diào)用時,里面的 events 參數(shù),這是用來進(jìn)行與 /apps/browser/index 頁面通訊,接收數(shù)據(jù)用的。

apps/browser/index.js

我省略了絕大多數(shù)與本文無關(guān)的代碼,保存最主要的三個:

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],
   });
  }
 },
})

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

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

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

H5 頁面的實(shí)現(xiàn)

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

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

wx.miniProgram.navigateBack()

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

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

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

這個頁面的功能其實(shí)很簡單,當(dāng)打開它了之后,做一點(diǎn)點(diǎn)小操作,立馬回退到上一個頁面(就是 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();

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

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

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

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

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

apps/browser/index.js 頁面

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

Page({
 data: {
  shouldReattachWebview: false, // 是否需要重新 attach 一次 webview 組件
  webviewReattached: false,   // 是否已經(jīng) attach 過一次 webview 了
  hideWebview: false      // 是否隱藏 webview 組件
 },
 onShow() {
  // 如果 webview 需要重新 attach 
  if (this.data.shouldReattachWebview) {
   this.setData(
    {
     // 隱藏 webview
     hideWebview: true,
    },
    () => {
     this.setData(
      {
       // 隱藏之后立馬顯示它,此時完成一次 webview 的銷毀,拿到了 postMessage 中的數(shù)據(jù)
       hideWebview: false,
       webviewReattached: true,
      },
      () => {
       // 拿到數(shù)據(jù)之后,處理 canvasData
       this.handleCanvasData();
      }
     );
    }
   );
  }
 },
 // 當(dāng) webview 被銷毀時,該方法被觸發(fā)
 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') {
   // 將數(shù)據(jù)先緩存進(jìn) Snap 中
   const { canvasData } = this.data;
   // app.checksum 是我自己封裝的方法,計(jì)算任何數(shù)據(jù)的 checksum,我拿它來當(dāng)作 key
   // 這可以保證同一條數(shù)據(jù)只會被處理一次
   const snapKey = app.checksum(data);
   // 只要未處理過的數(shù)據(jù),才需要再次數(shù)據(jù)
   if (canvasData[snapKey] !== true) {
    if (canvasData[snapKey] === undefined) {
     // 將數(shù)據(jù)從緩存進(jìn) `snap` 中
     // 這也是我自己封裝的一個方法,可以將數(shù)據(jù)緩存起來,并且只能被讀取一次
     app.snap(snapKey, data);
     // 設(shè)置 canvasData 中 snapKey 字段為 `false`
     canvasData[snapKey] = false;
     this.setData({
      canvasData,
     });
    }
   }
  }
 },
 // 當(dāng) webview 被重新 attach 之后,canvas 數(shù)據(jù)已經(jīng)被保存進(jìn) snap 中了,
 handleCanvasData: async function handleCanvasData() {
  const { canvasData } = this.data;
  // 從 canvasData 中拿到所有的 key,并過濾到已經(jīng)處理過的數(shù)據(jù)
  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;
   }
  }
 },
})

對應(yīng)的 index.wxml 文件內(nèi)容如下:

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

流程回顧與總結(jié)

  1. 打開 webview 頁面,打開 h6

  2. h6 頁面生成 canvas 圖,并轉(zhuǎn)為 base64 字符

  3. 通過 wx.miniProgram.postMessage 將 base64 發(fā)送給小程序

  4. 調(diào)用 wx.miniProgram.navigateTo 將頁面導(dǎo)向一個特殊頁面

  5. 在特殊頁面中,將 webview 所在頁面的 shouldReattachWebview 設(shè)置為 true

  6. 在特殊頁面中回退至 webview 所在頁面

  7. webview 所在頁面的 onShow 事件被觸發(fā)

  8. 在 onShow 事件檢測 shouldReattachWebview 是否為 true,若為 true

  9. 將 hideWebview 設(shè)置為 true,引起 web-view 組件的銷毀

  10. handlePostMessage 被觸發(fā),解析所有的 message 之后交給 handleMessage 逐條處理

  11. handleMessage 發(fā)現(xiàn) action === 'saveCanvas' 的事件,拿到 data

  12. 根據(jù) data 計(jì)算 checksum ,以 checksum 為 key 緩存下來數(shù)據(jù),并將這個 checksum 保存到 canvasData 對象中

  13. 此時 hideWebview 被 onShow 里面 setData 的回調(diào)中的 setData 重新置為 false,web-view 重新加 attach,H5頁面重新加載

  14. webview 重新 attach 之后, this.handleCanvasData 被觸發(fā),

  15. handleCanvasData 檢測是否有需要保存的 canvas 數(shù)據(jù),如果有,保存,修改 canvasData 狀態(tài)

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

感謝各位的閱讀!關(guān)于“微信小程序webview與h5通過postMessage實(shí)現(xiàn)實(shí)時通訊的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

網(wǎng)站題目:微信小程序webview與h5通過postMessage實(shí)現(xiàn)實(shí)時通訊的示例分析
標(biāo)題網(wǎng)址:http://www.ekvhdxd.cn/article43/gecphs.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航、定制網(wǎng)站、網(wǎng)站策劃、軟件開發(fā)、關(guān)鍵詞優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計(jì)