阅读 3620

公众号打开小程序最佳解决方案(Vue)

场景

  • 由于一些特殊的需求导致了项目的分离,当前的项目是在微信的公众号,部分需求要求用小程序来做,但是两者之间存在关联,需要通过公众号去跳转小程序。

技术方案

  • 使用微信网页的 JSSDK

适用环境

  • 微信版本要求为:7.0.12 及以上
  • 系统版本要求为:iOS 10.3 及以上、Android 5.0 及以上

具体步骤

  • 这部分是官方文档中的,我是挪过来方便大家看,也可以自己去官方文档看。 官方文档
  1. 绑定域名

    • 先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”
  2. 引入 JS 文件

    • 在需要调用 JS 接口的页面引入如下 JS 文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.6.0.js
    • 如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)。
    • 注:支持使用 AMD/CMD 标准模块加载方法加载
  3. 通过 config 接口注入权限验证配置

    • 所有需要使用 JS-SDK 的页面必须先注入配置信息,否则将无法调用(同一个 url 仅需调用一次,对于变化 urlSPAweb app 可在每次 url 变化时进行调用,目前 Android 微信客户端不支持 pushStateH5 新特性,所以使用 pushState 来实现 web app 的页面会导致签名失败,此问题会在 Android6.2 中修复)。
    wx.config({
      debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
      appId: '', // 必填,公众号的唯一标识
      timestamp: , // 必填,生成签名的时间戳
      nonceStr: '', // 必填,生成签名的随机串
      signature: '', // 必填,签名
      jsApiList: [], // 必填,需要使用的JS接口列表
      openTagList: ['wx-open-launch-weapp'] // 微信开放标签 小程序跳转按钮:<wx-open-launch-weapp>
    });
    复制代码
  4. 通过 ready 接口处理成功验证

    wx.ready(function(){
      // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
    });
    复制代码
  5. 通过 error 接口处理失败验证

    wx.error(function(res){
      // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
    });
    复制代码
  6. 通过请求后段接口拿到 config 需要的参数,去初始化后,在页面增加如下的标签

 // 请求 config需要的参数
 postUrl({url: curUrl}).then(res => {
     if (res.code === 0) {
         wx.config({
             debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
             appId: res.data.appId, // 必填,公众号的唯一标识
             timestamp: res.data.timeStamp, // 必填,生成签名的时间戳
             nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
             signature: res.data.signature, // 必填,签名
             jsApiList: ['onMenuShareAppMessage'],
             openTagList: ['wx-open-launch-weapp'] // 可选,需要使用的开放标签列表,例如['wx-open-launch-app']
         });
         wx.ready(function(){})
         wx.error(function(error){})
     }
 })

 // html
  <wx-open-launch-weapp
     id="launch-weapp1"
     username="gh_xxxxxx"
     path="xxxxxx"
     @launch="onLaunch"
     @error="onError"
 >
     <script type="text/wxtag-template">
         <div style="font-size: 14px;margin-top: 10px;text-align: center;">打开小程序</div>
     </script>
 </wx-open-launch-weapp>
复制代码

(1)username:要打开的小程序原始 idgh_ 开头的;
(2)path:要打开的小程序页面(页面最后要加.html,例如:'pages/index/index.html',否则 IOS 跳转时出现小程序页面未配置)

错误处理

  1. 标签报错

  • 解决方法:在 main.js 中添加以下代码;
// main.js
Vue.config.ignoredElements = ['wx-open-launch-weapp'];
复制代码
  1. wx-open-launch-weapp 中的 Dom 不显示
  • 当前wx-open-launch-weapp 标签中的 Dom 只有在真机下才会显示,在电脑端的浏览器、微信开发者工具中都不会显示;这就导致了一个问题 wx-open-launch-weapp 里面的内容控制、样式调试等很难,且渲染数据很麻烦。
  1. wx-open-launch-weapp 中的 Dom 显示,但真机点击无反应
  • 如果所使用的标签允许提供插槽,由于插槽中模版的样式是和页面隔离的,因此需要注意在插槽中定义模版的样式。插槽模版及样式均需要通过 <template></template> 进行包裹。对于 Vue 等视图框架,为了避免 template 标签冲突的问题,可使用 <script type="text/wxtag-template"><script> 进行代替,来包裹插槽模版和样式。
  1. 小程序无法打开
  • 这种方式只能打开合法合规的小程序且小程序已正式发布(体验版不行)。

优化

  • 当我们需要通过一个卡片或者有很多动态数据渲染一个大的 Dom 结构时,里面的样式写起来就十分的麻烦且动态设置里面的数据也很不方便,所以我们最好的方式就是不在 wx-open-launch-weapp 中写任何内容。
  • 经过我自己的尝试,我放弃了在 wx-open-launch-weapp 中写样式,因为那是在太麻烦了,一点改动就需要去部署,到真机上验证。

解决方案

  • 我们在需要跳转的地方,去生成一个包裹层,并将这个包裹层覆盖到点击区域的上方,然后设置背景色为透明色。并动态生成 wx-open-launch-weapp
  1. 添加包裹层
<div class="weapp-cover"></div>

// weapp-cover的宽高应该根据点击区域动态设置
.weapp-cover {
    z-index: 90;
    position: absolute;
    bottom: 16px;
    right: 26px;
    // background-color: red;
}
复制代码
  1. 动态设置包裹层宽高
mounted() {
  const weappDom = this.$el.querySelector('.weapp-cover');
  const menuItemDom = this.$el.querySelector('.menu-item');// 点击区域对象
  weappDom.style.width = menuItemDom.clientWidth + 'px';
  weappDom.style.height = menuItemDom.clientHeight + 'px';
}
复制代码
  1. 动态生成 wx-open-launch-weapp

/**
 * @description: 生成wx-open-launch-weapp
 * @param {Object} info 
 */

/* 
 * @description: info参数
let params={
    width: "", 点击区域宽度
    height: "", 点击区域高度
    ele:"", // 元素ID
    appid:"", // 小程序id号 gh_****
    url:"", // 跳转小程序的页面路径地址 例: pages/home/home.html - (后面必须带上.html后缀 否则IOS跳转时出现小程序页面未配置)
    content:"" // html字符串 例: "<button>点我</button>"
}
*/
export function wx_launch(info) {
      const btn = info.ele.querySelector('.weapp-cover'); //获取元素
      const script = document.createElement("script");// 创建script内容插槽 避免template标签冲突
      script.type = "text/wxtag-template"; // 使用script插槽 必须定义这个type
      script.text = info.content // 自定义的html字符串内容
      const html = `<wx-open-launch-weapp 
                      style="width:${info.width};
                      height:${info.height};
                      display:block;" username="${info.appid}" 
                      path="${info.url}">${script.outerHTML}</wx-open-launch-weapp>`;
      btn.innerHTML = html; // html字符串赋值
}
复制代码
  1. 增加微信浏览器判断
// 判断是否微信环境
function is_weixn() {
    let ua = navigator.userAgent.toLowerCase()
    if (ua.match(/MicroMessenger/i) == 'micromessenger') {
        return true
    } else {
        return false
    };
};
复制代码
  1. 增加微信版本判断
  • 在测试中发现部分人员的微信一直提示 您的版本号不支持,通过查看各个微信版本发现,获取的微信版本字符串不一致,有的是三位、有的是四位;
  const wxInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i); // 微信浏览器信息
  // 微信版本号 wxInfo[1]
  // 我们当前正常的版本
  wxInfo[1] = "8.0.1840"
  // 异常版本号
  wxInfo[1] = "8.0.1.1840"
复制代码
  • 微信版本要求为:7.0.12 及以上
  • 通过上述问题,我们可以修改 is_version 方法,先判断大版本号及第一位大于 7 时直接返回 true ,当等于 7 时,判断第二位是否大于 0,大于 0 直接返回 true,等于 0 时判断第三位是否大于等于 12。代码如下:
  // 判断当前微信版本号是否支持
  function is_version() {
      const wxInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i); // 微信浏览器信息
      // 微信正常版本号 wxInfo[1] = "8.0.1840" (示例)
      // 微信异常版本号 wxInfo[1] = "8.0.1.1840" (示例)
      //进行split转成数组进行判断 ['8','0','1','1840'] (示例)
      const version = wxInfo[1].split(".");
      // console.log('version', version);
      // 判断版本在7.0.12及以上的版本
      if (Number(version[0]) > 7) {
          return true;
      } else if (Number(version[0]) === 7) {
          if (Number(version[1]) > 0) {
              return true;
          } else if (Number(version[1]) === 0) {
              if (Number(version[2]) >= 12) return true;
          }
      }
      return false;
  }
复制代码
  • 注:字符串调用 split 方法后,数字在数组中为字符串。
  1. 修改动态生成wx-open-launch-weapp方法
export function wx_launch(info) {
+    if (!is_weixn()) {
+        return
+    }
+    if (is_version()) {
        const btn = info.ele.querySelector('.weapp-cover'); //获取元素
        ...
+    } else {
+        alert("您的版本号不支持")
+    }
复制代码
  1. 调用 wx_launch
mounted() {
  const weappDom = this.$el.querySelector('.weapp-cover');
  const menuItemDom = this.$el.querySelector('.menu-item');// 点击区域对象
  weappDom.style.width = menuItemDom.clientWidth + 'px';
  weappDom.style.height = menuItemDom.clientHeight + 'px';
  // 动态生成小程序跳转遮罩层
+  wx_launch({
+      ele: this.$el,
+      width: menuItemDom.clientWidth + 'px',
+      height: menuItemDom.clientHeight + 'px',
+      appid: 'gh_xxxx',
+      url: this.miniProgramPath,
+      content: 
+          `<style>
+              .res-cover {
+                  width: ${menuItemDom.clientWidth}px;
+                  height: ${menuItemDom.clientHeight}px;
+              }
+          </style> 
+          <div class="res-cover"></div>`
+  })
}
复制代码

总结

  • 拿到需求后,首先是去是否有相关的技术方案能实现这样的功能;有技术方案时,通过分析需求看需要怎么样的实现以及可能遇到的问题;
  • 自己遇到的坑:错误处理中的 4 个问题都遇到过、wx-open-launch-weapp 中的内容显示样式问题及卡片数据无法动态渲染问题、动态生成 wx-open-launch-weappDom 找不到等很多小问题;
  • 在已实现功能后,我们可以通过一些奇技淫巧或间接方法去达到我们所想的预期,不要被需求局限了思维。

补充

  • 后续问题在这里补充说明
    1. URL 带参数跳转小程序,小程序接收不全,跳转 URL 如下所示:
    小程序接收到的是 "Source=public&token={",原因是由于 token 是一个对象通过 JSON.stringify 生成的字符串,URL 通过模版字符串生成的插入 token 生成的,导致小程序接收时对引号进行了截断,所以我们需要在生成的对象类型字符串使用 encodeURI 进行 URL 编码。
      const pathStr = 'pages/detail/speakingDetail.html?Source=public';
      let tokenParams = {};
      const miniProgramUrl = `${pathStr}&token=${encodeURI(JSON.stringify(tokenParams))}`;
    复制代码
    1. iOS 系统跳转 URL 会有问题,原因是 iOSencodeURI 编码方式不支持,替换为 encodeURIComponent 即可。(注:这种方式编码后,小程序接收的地方需要解码)
    2. 在跳转小程序后,某些情况可能需要关闭当前的公众号网页,通过 addEventListener 添加 launch 事件无法触发;
    [dom].addEventListener("launch", function (e) {
        //     console.log("success");
        // });
    复制代码
    解决方法:在需要的地方,动态为需要的 dom 添加 lanunch 事件,通过 info 的某个参数判断是够需要 launch 事件,再加上一个对应的需要时执行的回调即可。
    
    export function wx_launch(info) {
    ...
     +   var launchScript = document.createElement("script");
     +   launchScript.type = "text/javascript";
     +   if (info.needLaunch) {
     +      launchScript.appendChild(document.createTextNode(
     +           `var btn = document.getElementById('launch-btn');
     +           btn.addEventListener('launch', function (e) {\n
     +               WeixinJSBridge.call('closeWindow'); // info.callback
     +          });`
     +       ));
     +      btn.appendChild(launchScript)
     +   }
     -   btn.addEventListener("launch", function (e) {
     -      console.log("success");
     -   });
    复制代码
    注:WeixinJSBridge.call('closeWindow') 是关闭当前浏览器,回到公众号对话窗口。只在微信浏览器生效。

参考

更多优质文章

「点赞、收藏和评论」

❤️关注+点赞+收藏+评论+转发❤️,原创不易,鼓励笔者创作更好的文章,谢谢🙏大家。

文章分类
前端
文章标签