uniapp中用webview嵌套另一个uniapp编译的H5项目,如何实现通信?

3,077 阅读1分钟

这是一个翻遍全网都很难解决的bug,终于在我的反复尝试下,轻松实现。

先陈述我的问题:

有a和b两个项目,都是uniapp开发,a编译成小程序,b编译成h5,a中用webview嵌套b,如何实现b向a通信?

首先,官方提供的 uni.postMessage 目前实测很难生效,因为它有个限定条件:

image.png

但要解决问题,依然需要靠它这一点。话不多说,直接上代码:

1、A项目中【被编译为小程序或H5】

<template>
    <view>
        <web-view :src="webviewUrl" style="width:100vw;height:100vh;" @message="messageFn"></web-view>
    </view>
</template>

<script>
export default {
    name: "mall",
    data(){
        return {
            webviewUrl: "xxxxx"
        }
    },
    methods: {
        // 监听嵌套的H5页面发过来的信息
        messageFn(e) {
            // console.log('收到iframe页面内容:', e.data)
            if (!e.data.data) return;
            if (e.data.data.arg !== 'back') return;
            // 监听到web-view通知back,去处理你想做的事情,这里我是做了导航到首页
            uni.navigateTo({
                url: "/pages/index/index",
            });
        },
    },
    mounted() {
        // #ifdef H5
        // A项目运行在H5时,如果不加这句代码,真机运行的时候,就无法监听到message事件
        window.addEventListener("message", this.messageFn, false)
        // #endif
    },
}
</script>

2、B项目中【被编译为H5】

B项目就是打包为H5,并将服务器地址作为 webviewUrl 放到A项目的 <web-view /> 中。 这里要注意,B项目中的postMessage想要让A项目(小程序端)直接收到,必须写在纯粹的html文件中,不能是通过webpack这类工具打包出来的项目。

所以需要在B项目中创建一个桥页 bridge.html(就是一个过渡页面,用完就跳走),页面我放在 /static/html/ 下代码很简单:

<!DOCTYPE html>
<html lang="zh">
    <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
    </head>
    <body>
        桥页 - <span id="sp"></span>
    </body>
</html>
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script>
    document.getElementById('sp').innerHTML = window.location.origin+'/gov/'

    wx.miniProgram.navigateTo({
        url: "/pages/index/index",
    });

    // 跳转页面随便跳,我是回退一层页面,因为回退页面也可以触发页面的销毁,使A项目中@message能生效
    window.location.go(-1);
</script>

上面引入了 jweixin-1.4.0.js,是为了在小程序环境(B目前是被放在A这个小程序中)下可以直接使用微信的API。

最后就是B项目中原本你想要发送数据给A项目的页面中(也就是跳转去桥页的那个vue文件):

<template>
    <view class="union_page">
       <!-- 此页面用于跳转到bridge.html,通过页面销毁引起postMessage生效 -->
    </view>
</template>

<script>
    // #ifndef MP-WEIXIN
    import web from '@/utils/js/uni.webview.1.5.4.js'  // 自行下载
    // #endif

    export default {
        mounted() {
            // 以下代码当商城嵌入在H5时生效
            // #ifndef MP-WEIXIN
            const webview = web.webView
            if (typeof webview !== "undefined") {
                    webview.postMessage({ data: "back" });
            }
            // #endif

            // 以下代码当商城嵌入在小程序时生效
            let msg = JSON.stringify({data: 'back'})  // 这里记得序列化
            if(window){
                window.parent.postMessage(msg, "*")

                window.location.href = window.location.origin+'/static/html/bridge.html';
            }
        }
    }
</script>

如此就完成啦! 我这里保留了最基础的代码,其他的业务代码就不展示出来了。uni.webview.1.5.4.jsjweixin-1.4.0.js 插件网上很多,大家可以自己百度。