解决微信内置浏览器使用Vue时开放标签无效的问题

提醒:本文最后更新于 852 天前,文中所描述的信息可能已发生改变,请谨慎使用。

最近用 Vue 开发一个公众号网页项目,其中有一个需求是点击按钮跳转到小程序;在开发时发现偶然会出现开放标签不显示的问题,经过几天的探究,终于解决了这个问题,写个帖子记录下。

开放标签不显示

发现这个问题后仔细排查了一下,发现 Android 上面没有这个问题。而 iOS 上通过 Vue 的路由导航到使用了开放标签的页面时,标签不会显示;只有直接进入此页面或者刷新页面之后开放标签才会生效。

网上搜了一圈,这个问题几年前就有了,微信开放社区一堆相关问题,官方至今没有回应,日常问候一下小龙全家。在我正焦头烂额之际,看到了这个帖子,一楼的回答完美解决了我的问题。

在生成签名时,我们一般都传递的是location.href.split("#")[0],而 iOS 微信浏览器上使用单页面应用时,无论如何通过路由导航跳转到其他页面,微信浏览器会一直认为我们的当前页面路径是第一次进入此应用的路径;所以只有在刷新或者直接进入使用了开放标签的页面时,开放标签才会正常生效;这样一来,解决方案就很简单了,Android 正常使用location.href.split("#")[0],而在 iOS 上将初次进入页面的页面路径保存下来,后续进行签名时使用保存的路径即可。

// path.js

// 保存初次进入的路径,根据不同平台返回不同的路径

const path = location.href.split("#")[0];

const isIos = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);

export const getCurrentUrl = () => isIos ? path : location.href.split("#")[0];
// api.js

// 获取微信签名的接口

import { getCurrentUrl } from "./path.js";

export function getWechatConfig() {
    return http.get("wechat/config", {
        url: getCurrentUrl()
    });
}

开放标签样式

说点题外话,本次项目是使用rem做的页面适配,而开放标签内部样式是和外部隔绝的;好死不死设计图上正好有两个并排的相同样式的按钮,一个按钮是普通标签,另一个按钮是开放标签;为了使两个按钮样式一样,我刚开始使用的办法是将涉及到尺寸之外的样式在开放标签内写死,而涉及到rem尺寸的则将其转为px,再通过拼接字符串的形式补全标签内容,代码如下:

const renderOpenTagWeApp(btnText, username, path) {
    const baseFontSize = Number(document.documentElement.style.fontSize.replace('px', ''));
    // 获取当前根元素的字体大小

    const remToPx = (rem) => rem * baseFontSize;
    // 将 rem 转为 px

    return `
        <wx-open-launch-weapp username="${username}" path="${path}"> 
            <script type="text/wxtag-template">
                <style>
                    .btn {
                        ...
                        ...

                        font-size: ${remToPx(0.23)}px;
                        height: ${remToPx(0.47)}px;
                        width: ${remToPx(1.31)}px;
                        border-radius: ${remToPx(0.23)}px;
                    }
                </style>
                <div class="btn">${btnText}</div>
            </script>
        </wx-open-launch-weapp>`;
}

想象很美好,现实很骨感,设计图上的rem尺寸转换成px之后成为了无限小数,在屏幕上就有了肉眼可见的尺寸差距,这可不行;折腾了半天之后终于有了解决办法,既然开放标签内部的样式无法和外部保持完全一致,那就索性让开放标签不展示内容,使用一个普通元素来展示内容,让开放标签的容器标签wx-open-launch-weapp通过绝对定位占满普通元素的内部,开放标签内部则只使用一个空白div标签,这样一来样式可以完美还原设计图,同时开放标签的功能也不会受到影响。

.pos {
    position: relative;
}

.abs {
    position: absolute;
}

.full {
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
}
const renderOpenTagWeApp(username, path) {
    const baseFontSize = Number(document.documentElement.style.fontSize.replace('px', ''));

    const remToPx = (rem) => rem * baseFontSize;

    return `
        <wx-open-launch-weapp class="abs full" username="${username}" path="${path}"> 
            <script type="text/wxtag-template">
                <style>
                    .btn {
                        height: ${remToPx(0.47)}px;
                        width: ${remToPx(1.31)}px;
                    }
                </style>
                <div class="btn"></div>
            </script>
        </wx-open-launch-weapp>`;
}
<template>
    <div class="pos">
        跳转小程序

        <div class="abs full" v-html="renderOpenTagWeApp('gh_xxxxxx', 'pages/index/index')"></div>
        /* 负责承载开放标签内容的div */

    </div>

</template>

Powered By Hexo & Theme Veni