使用uniapp实现支付宝小程序webview与h5通信以及踩坑记录

2,280 阅读2分钟

摘要

本文记录了菜鸟作者在使用uniapp开发项目的过程中,遇到的众多问题中的一个:在开发支付宝小程序的webview与h5页面通信功能时遇到的坑,postMessage通信时h5页面跳转到webview首次打开的h5页面现象。

吐槽:兼容,多好听的词儿。

前言

开发工具: uniapp 3.1.18;支付宝小程序开发者工具 2.0 Stable

正文

内容不多,本文只做简述。

使用uniapp开发支付宝小程序时,使用webview打开h5页面后,可以通过@message事件和webViewContext.postMessage实现双向通信。以下展示代码:

小程序端的代码如下:

<web-view :src="src" @message="getMessage" ></web-view>
let webViewContext;

export default {
    data() {
        return {
            src: '',
        };
    },
    methods: {
        /**
         * 接收信息
         */
        getMessage(e){
            console.log("getMessage: ", e);
            let method = e.detail.method;
            let param = e.detail.param;

            if (!webViewContext) {
                webViewContext = my.createWebViewContext(e.target.id);
            }

            if (method == 'login') {
                // todo something
            }

            if (method == "fedLogout") {
                // todo something
            }

            if (method == "close") {
                // todo something
            }
        },

        /**
         * 发送信息
         */
        postMessage({method, data, code=200, msg}){
            webViewContext.postMessage({
                method: method,
                data: data,
                code: code,
                msg: msg
            });
        },
    }
};

细心的朋友可能发现了,webViewContext前面没有“this.”,这里没有写错,是故意的。为什么这么写,等稍后解释。

接下来是h5端的代码:

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <title>
            <%= htmlWebpackPlugin.options.title %>
        </title>
        <script>
            // 引入支付宝jssdk
            if (navigator.userAgent.indexOf('AlipayClient') > -1) {
                document.writeln('<script src="https://appx/web-view.min.js"' + '>' + '<' + '/' + 'script>');
            }
        </script>
        <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
    </head>
    <body>
        <noscript>
            <strong>Please enable JavaScript to continue.</strong>
        </noscript>
        <div id="app"></div>
        <!-- built files will be auto injected -->
    </body>
</html>
function login () {
    return new Promise((resolve, reject) => {
        /**
         * 和小程序通信
         */
        my.postMessage({
                method: "login"
        });

        /**
         * 监听小程序
         */
        my.onMessage = function(response) {
                console.log(response);
                if (response.method == "login") {
                        if (response.code == 200) {
                                resolve(response.data);
                        } else {
                                reject(response.msg);
                        }
                }
        };
    });
}

接下来说明一下,为什么不把webViewContext放在data里面,而是单独声明。

不卖关子,原因就是如果把webViewContext放在data中,当webViewContext变化时,会触发vue页面重新渲染,即使这个webViewContext没有放在页面元素里。当然,不只是webViewContext,只要是有可能变化的字段,都不能往data里放。这个小坑可是浪费了我不少时间!!!

作者水平有限,没有找到比较优雅的解决方法,为了解决这个问题,直接把webViewContext等字段放在了外面。如果有大佬知道怎么处理,还请不吝赐教。

后记

说一点题外话。

人生不如意,十之八九。就算你在某一方面有多努力,别人总会在其他方面指责你的不足。你尽力帮别人解决问题,未必就能够得到好的回报。

人还是得自己逗自己开心。不像我,只会心疼作者。