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通信方式,答案也不靠谱。

uniapp企业微信web-view父子通信问题


参考资料


©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀

原文链接:https://juejin.cn/post/7242339570145869883 作者:安木夕

(0)
上一篇 2023年6月8日 上午11:12
下一篇 2023年6月9日 上午10:05

相关推荐

发表回复

登录后才能评论