uniapp企業微信web-view父子通信問題

項目背景:開發工具爲HBuilderX,框架爲uniapp,開發移動端的Web應用,在企業微信中使用(自建應用),Web開發的應用,不是小程序。

需求:頁面中用到<web-view>組件,加載其他系統的頁面(有跨域),需要在父子頁面之間相互通信。這裏通信的東西其實就是獲取定位,通過uniapp獲取用戶定位信息,傳遞給<web-view>內的頁面用於地圖的展示和其他業務需求。獲取定位也是遇到了一些問題,參考另一篇記錄《uniapp企業微信應用中的定位問題

<web-view :src="https://****"></web-view>

<web-view>內部其實就是iframe,因此本質上也就是要實現iframe的(跨域)父子通信。

原始方案:URL傳遞

在uniapp中獲取定位數據,通過URL參數的方式傳遞給<web-view>的頁面。

<web-view :src="https://****?&longitude=${longitude}&latitude=${latitude}"></web-view>

這個方法弊端很多,不得不拋棄。

  • 🚫性能影響&用戶體驗:很多時候<web-view>內的子頁面是不需要該定位數據的,只要當有用到地圖組件時,才需要獲取定位。這種方式不管要不要,都處理(獲取、發送),很影響性能,而且企業微信中獲取定位會彈出定位授權提示。
  • 🚫重複加載頁面,而且會導致<web-view>加載多次,因爲獲取定位是異步的,參數變化會影響url(src)的變更,觸發頁面重新加載。

web-view相互通信

優化目標是在需要加載地圖組件時,向父頁面(uniapp)發送請求指令,父頁面(uniapp)獲取定位信息後,發送給子頁面,按需獲取。

基本的技術思路就是利用window/unipostMessageonmessage來實現相互通信。但實際上由於uniapp面向各種不同的場景,如小程序、移動App、企業微信H5應用,實現方式略有不同,網上各種方案不一定行得通,因此記錄一下解決過程。

在子頁面發送指令

子頁面給父頁面(uniapp)發送指令,請求獲取定位信息,使用了uniapp提供的一個SDK來實現。

  • window.uni.postMessage()方法發送指令信息。
  • window.onmessage事件接收消息。
mounted() {
  // 發送消息指令
  window.uni.postMessage({ data: { type: 'getLocation' } })
  // 等待接收消息
  window.onmessage = (e) => {
    if (e.data?.getLocation) {
      console.log('e.data?.getLocation', e.data.getLocation)
      this.point = e.data?.getLocation
      this.asyncInitMap()
    }
  }
},

這裏的uniuniapp提供的一個SDK,在程序中引用JS文件。

<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>

在uniapp父頁面中接收、響應

  • window.onmessage事件接收消息指令,判斷是否約定的指令。
  • 獲取定位併發送,發送通過this.$refs.webview.iframe.contentWindow.postMessage(res, url)方法發送定位結果給子頁面。
  • 注意的是,第一個參數爲要發送的數據,第二個參數爲目標域名,否則會發送失敗(不同域名)。
<template>
  <web-view :src="src" ref="webview"></web-view>
</template>

<script>
  import webview from './webview'
  import getLocation from './Location.js'
  export default {
    mixins: [webview],
    data() {
      return {
        src: '',
      };
    },
    onLoad(options) {
      this.src = 'http://****/q=**'
      //接收指令
      window.onmessage = (e) => {
        //判斷指令
        if(e.data?.data?.arg?.type === 'getLocation'){
          //獲取定位併發送過去
          getLocation().then(res => {
            this.$refs.webview.iframe.contentWindow.postMessage({getLocation:res},this.webviewServer)
          }).catch(err => console.log(err))
        }
      }
    },
  }
</script>

這一步藉助了chartGPT(3.5版本)的幫助,當然也是經過多輪對話才找到一點可用的,直接問他uniapp中的webview通信方式,答案也不靠譜。

image.png


參考資料


©️版權申明:版權所有@安木夕,本文內容僅供學習,歡迎指正、交流,轉載請註明出處!原文編輯地址-語雀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章