国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專(zhuān)題視頻專(zhuān)題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專(zhuān)題1關(guān)鍵字專(zhuān)題50關(guān)鍵字專(zhuān)題500關(guān)鍵字專(zhuān)題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關(guān)鍵字專(zhuān)題關(guān)鍵字專(zhuān)題tag2tag3文章專(zhuān)題文章專(zhuān)題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專(zhuān)題3
問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

微信小程序webview與h5通過(guò)postMessage實(shí)現(xiàn)實(shí)時(shí)通訊的實(shí)現(xiàn)

來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 21:52:05
文檔

微信小程序webview與h5通過(guò)postMessage實(shí)現(xiàn)實(shí)時(shí)通訊的實(shí)現(xiàn)

微信小程序webview與h5通過(guò)postMessage實(shí)現(xiàn)實(shí)時(shí)通訊的實(shí)現(xiàn):在做 React Native 應(yīng)用時(shí),如果需要在 App 里面內(nèi)嵌 H5 頁(yè)面,那么 H5 與 App 之間可以通過(guò) Webview 的 PostMessage 功能實(shí)現(xiàn)實(shí)時(shí)的通訊,但是在小程序里面,雖然也提供了一個(gè) webview 組件,但是,在進(jìn)行 postMessage 通訊時(shí),官方文檔里面給
推薦度:
導(dǎo)讀微信小程序webview與h5通過(guò)postMessage實(shí)現(xiàn)實(shí)時(shí)通訊的實(shí)現(xiàn):在做 React Native 應(yīng)用時(shí),如果需要在 App 里面內(nèi)嵌 H5 頁(yè)面,那么 H5 與 App 之間可以通過(guò) Webview 的 PostMessage 功能實(shí)現(xiàn)實(shí)時(shí)的通訊,但是在小程序里面,雖然也提供了一個(gè) webview 組件,但是,在進(jìn)行 postMessage 通訊時(shí),官方文檔里面給

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

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

  1. 用戶做了回退到上一頁(yè)的操作
  2. 組件銷(xiāo)毀
  3. 用戶點(diǎn)擊了分享

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

wx.miniProgram.navigateBack()

大體思路

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

第 1 種方式:回退

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

  1. 處理 postMessage 信息
  2. 回退到上一頁(yè)

我們?cè)谔幚?postMessage 的時(shí)候做一些特殊操作,可以將這些數(shù)據(jù)保存下來(lái)

第 2 種方式:組件銷(xiāo)毀

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

  1. 小程序 postMessage
  2. 小程序 navigateTo 將小程序頁(yè)面導(dǎo)向一個(gè)特殊的頁(yè)面
  3. 小程序的那個(gè)特殊頁(yè)面立馬回退到 webview 所在的頁(yè)面
  4. webview 所在的頁(yè)面的 onShow 里面,做一次處理,將 webview 銷(xiāo)毀,然后再次打開(kāi)
  5. 觸發(fā) onMessage 拿到數(shù)據(jù)
  6. H5 頁(yè)面再次被打開(kāi)

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

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

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

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)用時(shí),里面的 events 參數(shù),這是用來(lái)進(jìn)行與 /apps/browser/index 頁(yè)面通訊,接收數(shù)據(jù)用的。

apps/browser/index.js

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

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 版本開(kāi)始提供的 getOpenerEventChannel 方法,它可以創(chuàng)建一個(gè)與上一個(gè)頁(yè)面的事件通訊通道,這個(gè)我們會(huì)在 handleMessage 中使用。

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

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

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

我的 H5 主要就是使用 html2canvas 庫(kù)生成 Canvas 圖(沒(méi)辦法,自己在小程序里面畫(huà)太麻煩了),但是這個(gè)不在本文討論過(guò)程中,我們就當(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() ,來(lái)觸發(fā)一次回退,也就觸發(fā)了 bindmessage 事件。

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

H5 頁(yè)面的改變

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

wx.miniProgram.navigateTo('/apps/browser/placeholder');

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

/apps/browser/placeholder

這個(gè)頁(yè)面的功能其實(shí)很簡(jiǎn)單,當(dāng)打開(kāi)它了之后,做一點(diǎn)點(diǎn)小操作,立馬回退到上一個(gè)頁(yè)面(就是 webview 所在的頁(yè)面。

Page({
 data: { loading: true },
 onLoad(options) {

 const pages = getCurrentPages();

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

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

我們一行一行來(lái)看:

const pages = getCurrentPages();

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

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

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

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

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

apps/browser/index.js 頁(yè)面

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

Page({
 data: {
 shouldReattachWebview: false, // 是否需要重新 attach 一次 webview 組件
 webviewReattached: false, // 是否已經(jīng) attach 過(guò)一次 webview 了
 hideWebview: false // 是否隱藏 webview 組件
 },
 onShow() {
 // 如果 webview 需要重新 attach 
 if (this.data.shouldReattachWebview) {
 this.setData(
 {
 // 隱藏 webview
 hideWebview: true,
 },
 () => {
 this.setData(
 {
 // 隱藏之后立馬顯示它,此時(shí)完成一次 webview 的銷(xiāo)毀,拿到了 postMessage 中的數(shù)據(jù)
 hideWebview: false,
 webviewReattached: true,
 },
 () => {
 // 拿到數(shù)據(jù)之后,處理 canvasData
 this.handleCanvasData();
 }
 );
 }
 );
 }
 },
 // 當(dāng) webview 被銷(xiāo)毀時(shí),該方法被觸發(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,我拿它來(lái)當(dāng)作 key
 // 這可以保證同一條數(shù)據(jù)只會(huì)被處理一次
 const snapKey = app.checksum(data);
 // 只要未處理過(guò)的數(shù)據(jù),才需要再次數(shù)據(jù)
 if (canvasData[snapKey] !== true) {
 if (canvasData[snapKey] === undefined) {
 // 將數(shù)據(jù)從緩存進(jìn) `snap` 中
 // 這也是我自己封裝的一個(gè)方法,可以將數(shù)據(jù)緩存起來(lái),并且只能被讀取一次
 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,并過(guò)濾到已經(jīng)處理過(guò)的數(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);
 // 通過(guò)自己封裝的方法,將 url(也就是Base64字符)保存至相冊(cè)
 const saved = await app.saveImages(url);
 // 更新 canvasData 對(duì)象
 canvasData[key] = true
 this.setData({
 canvasData
 })
 console.log('saved: ', saved);
 } catch (error) {
 app.toast(error.message);
 return;
 }
 }
 },
})

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

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

流程回顧與總結(jié)

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

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

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

微信小程序webview與h5通過(guò)postMessage實(shí)現(xiàn)實(shí)時(shí)通訊的實(shí)現(xiàn)

微信小程序webview與h5通過(guò)postMessage實(shí)現(xiàn)實(shí)時(shí)通訊的實(shí)現(xiàn):在做 React Native 應(yīng)用時(shí),如果需要在 App 里面內(nèi)嵌 H5 頁(yè)面,那么 H5 與 App 之間可以通過(guò) Webview 的 PostMessage 功能實(shí)現(xiàn)實(shí)時(shí)的通訊,但是在小程序里面,雖然也提供了一個(gè) webview 組件,但是,在進(jìn)行 postMessage 通訊時(shí),官方文檔里面給
推薦度:
標(biāo)簽: 小程序 微信小程序 通訊
  • 熱門(mén)焦點(diǎn)

最新推薦

猜你喜歡

熱門(mén)推薦

專(zhuān)題
Top
主站蜘蛛池模板: 免费h视频在线观看 | 日韩 国产 欧美 精品 在线 | 欧美第四页 | 亚洲欧美另类专区 | 久久精品国产欧美成人 | 免费看成人国产一区二区三区 | 极品久久 | 欧洲欧美成人免费大片 | 一道精品一区二区三区 | 国产观看 | 卡通动漫第一页 | 日韩视频中文字幕专区 | 亚洲第8页 | 欧美区一区二区三 | 香蕉久久精品 | 国产精品免费视频网站 | 国产最新精品视频 | 欧美精品一区二区三区免费观看 | 亚洲色图 第一页 | 日韩欧美不卡一区二区三区 | 快播电影网日韩新片 | 亚州一区二区 | 亚洲欧美日韩第一页 | 日韩国产免费一区二区三区 | 在线日韩欧美一区二区三区 | 国产精品亚洲精品日韩动图 | 亚洲国产精品热久久 | 91在线 | 欧美 | 国产成人精品一区二区三区 | 国产高清视频 | 国产精品亚洲片在线观看不卡 | 精品久久久久久久 | 国产观看 | 在线免费观看国产精品 | 国产综合精品久久久久成人影 | 日本精品在线观看 | 欧美精| 中文国产成人精品久久一区 | 欧美国产日韩另类 | 久久久久成人精品一区二区 | 午夜在线免费视频 |